summaryrefslogtreecommitdiff
path: root/chromium/ui
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 16:23:34 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:37:21 +0000
commit38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch)
treec4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/ui
parente684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff)
downloadqtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui')
-rw-r--r--chromium/ui/OWNERS3
-rw-r--r--chromium/ui/accelerated_widget_mac/window_resize_helper_mac.cc3
-rw-r--r--chromium/ui/accessibility/BUILD.gn21
-rw-r--r--chromium/ui/accessibility/accessibility_switches.cc18
-rw-r--r--chromium/ui/accessibility/accessibility_switches.h6
-rw-r--r--chromium/ui/accessibility/ax_action_handler.cc (renamed from chromium/ui/accessibility/ax_host_delegate.cc)14
-rw-r--r--chromium/ui/accessibility/ax_action_handler.h (renamed from chromium/ui/accessibility/ax_host_delegate.h)28
-rw-r--r--chromium/ui/accessibility/ax_enum_util.cc14
-rw-r--r--chromium/ui/accessibility/ax_enums.mojom24
-rw-r--r--chromium/ui/accessibility/ax_event_bundle_sink.h41
-rw-r--r--chromium/ui/accessibility/ax_event_generator.cc52
-rw-r--r--chromium/ui/accessibility/ax_event_generator.h22
-rw-r--r--chromium/ui/accessibility/ax_event_generator_unittest.cc35
-rw-r--r--chromium/ui/accessibility/ax_generated_tree_unittest.cc6
-rw-r--r--chromium/ui/accessibility/ax_language_info_unittest.cc172
-rw-r--r--chromium/ui/accessibility/ax_mode_observer.h6
-rw-r--r--chromium/ui/accessibility/ax_node.cc337
-rw-r--r--chromium/ui/accessibility/ax_node.h44
-rw-r--r--chromium/ui/accessibility/ax_node_data.cc87
-rw-r--r--chromium/ui/accessibility/ax_node_data.h20
-rw-r--r--chromium/ui/accessibility/ax_node_position_unittest.cc536
-rw-r--r--chromium/ui/accessibility/ax_position.h3
-rw-r--r--chromium/ui/accessibility/ax_role_properties.cc41
-rw-r--r--chromium/ui/accessibility/ax_role_properties.h8
-rw-r--r--chromium/ui/accessibility/ax_table_info.cc44
-rw-r--r--chromium/ui/accessibility/ax_table_info.h7
-rw-r--r--chromium/ui/accessibility/ax_tree.cc364
-rw-r--r--chromium/ui/accessibility/ax_tree.h195
-rw-r--r--chromium/ui/accessibility/ax_tree_combiner_unittest.cc32
-rw-r--r--chromium/ui/accessibility/ax_tree_data.cc6
-rw-r--r--chromium/ui/accessibility/ax_tree_fuzzer.cc28
-rw-r--r--chromium/ui/accessibility/ax_tree_id.cc62
-rw-r--r--chromium/ui/accessibility/ax_tree_id.h33
-rw-r--r--chromium/ui/accessibility/ax_tree_id_registry.cc63
-rw-r--r--chromium/ui/accessibility/ax_tree_id_registry.h36
-rw-r--r--chromium/ui/accessibility/ax_tree_observer.cc12
-rw-r--r--chromium/ui/accessibility/ax_tree_observer.h152
-rw-r--r--chromium/ui/accessibility/ax_tree_serializer.h30
-rw-r--r--chromium/ui/accessibility/ax_tree_source_checker.h155
-rw-r--r--chromium/ui/accessibility/ax_tree_unittest.cc708
-rw-r--r--chromium/ui/accessibility/ax_tree_update.h4
-rw-r--r--chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_te.xtb6
-rw-r--r--chromium/ui/accessibility/mojom/ax_action_data_mojom_traits_unittest.cc6
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits_unittest.cc16
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_id.mojom12
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.cc18
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.h17
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits_unittest.cc25
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node.cc3
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc544
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux.h9
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc590
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base.cc43
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base.h11
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate.h30
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc68
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h30
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.cc198
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.h4
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc276
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_relation_win.cc1
-rw-r--r--chromium/ui/accessibility/platform/compute_attributes.cc127
-rw-r--r--chromium/ui/accessibility/platform/compute_attributes.h25
-rw-r--r--chromium/ui/accessibility/platform/test_ax_node_wrapper.cc65
-rw-r--r--chromium/ui/accessibility/platform/test_ax_node_wrapper.h9
-rw-r--r--chromium/ui/android/BUILD.gn88
-rwxr-xr-xchromium/ui/android/build/create_ui_locale_resources.py88
-rw-r--r--chromium/ui/android/delegated_frame_host_android_unittest.cc102
-rw-r--r--chromium/ui/android/features.gni7
-rw-r--r--chromium/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java364
-rw-r--r--chromium/ui/android/junit/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcpTest.java169
-rw-r--r--chromium/ui/android/junit/src/org/chromium/ui/modelutil/PropertyModelTest.java219
-rw-r--r--chromium/ui/android/junit/src/org/chromium/ui/modelutil/SimpleListObservableTest.java107
-rw-r--r--chromium/ui/android/junit/src/org/chromium/ui/text/SpanApplierTest.java26
-rw-r--r--chromium/ui/android/overscroll_refresh.cc30
-rw-r--r--chromium/ui/android/overscroll_refresh.h4
-rw-r--r--chromium/ui/android/overscroll_refresh_handler.cc12
-rw-r--r--chromium/ui/android/overscroll_refresh_handler.h6
-rw-r--r--chromium/ui/android/overscroll_refresh_unittest.cc4
-rw-r--r--chromium/ui/android/resources/resource_factory.cc5
-rw-r--r--chromium/ui/android/window_android.cc24
-rw-r--r--chromium/ui/aura/BUILD.gn16
-rw-r--r--chromium/ui/aura/client/aura_constants.cc10
-rw-r--r--chromium/ui/aura/client/aura_constants.h17
-rw-r--r--chromium/ui/aura/client/drag_drop_delegate.cc8
-rw-r--r--chromium/ui/aura/client/drag_drop_delegate.h4
-rw-r--r--chromium/ui/aura/client/window_types.h3
-rw-r--r--chromium/ui/aura/demo/demo_main.cc2
-rw-r--r--chromium/ui/aura/env.h2
-rw-r--r--chromium/ui/aura/mus/client_side_window_move_handler.cc115
-rw-r--r--chromium/ui/aura/mus/client_side_window_move_handler.h49
-rw-r--r--chromium/ui/aura/mus/client_surface_embedder.cc1
-rw-r--r--chromium/ui/aura/mus/drag_drop_controller_mus.cc43
-rw-r--r--chromium/ui/aura/mus/drag_drop_controller_mus.h19
-rw-r--r--chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc7
-rw-r--r--chromium/ui/aura/mus/focus_synchronizer_unittest.cc6
-rw-r--r--chromium/ui/aura/mus/in_flight_change.cc7
-rw-r--r--chromium/ui/aura/mus/in_flight_change.h6
-rw-r--r--chromium/ui/aura/mus/input_method_mus.cc28
-rw-r--r--chromium/ui/aura/mus/input_method_mus_unittest.cc13
-rw-r--r--chromium/ui/aura/mus/mus_context_factory.cc7
-rw-r--r--chromium/ui/aura/mus/mus_lsi_allocator.cc115
-rw-r--r--chromium/ui/aura/mus/mus_lsi_allocator.h119
-rw-r--r--chromium/ui/aura/mus/os_exchange_data_provider_mus.cc39
-rw-r--r--chromium/ui/aura/mus/os_exchange_data_provider_mus.h6
-rw-r--r--chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc6
-rw-r--r--chromium/ui/aura/mus/property_converter.cc40
-rw-r--r--chromium/ui/aura/mus/property_converter.h3
-rw-r--r--chromium/ui/aura/mus/property_utils.cc2
-rw-r--r--chromium/ui/aura/mus/text_input_client_impl.cc4
-rw-r--r--chromium/ui/aura/mus/text_input_client_impl.h1
-rw-r--r--chromium/ui/aura/mus/window_mus.h16
-rw-r--r--chromium/ui/aura/mus/window_port_mus.cc205
-rw-r--r--chromium/ui/aura/mus/window_port_mus.h48
-rw-r--r--chromium/ui/aura/mus/window_port_mus_unittest.cc109
-rw-r--r--chromium/ui/aura/mus/window_tree_client.cc76
-rw-r--r--chromium/ui/aura/mus/window_tree_client.h29
-rw-r--r--chromium/ui/aura/mus/window_tree_client_unittest.cc80
-rw-r--r--chromium/ui/aura/mus/window_tree_host_mus.cc89
-rw-r--r--chromium/ui/aura/mus/window_tree_host_mus.h5
-rw-r--r--chromium/ui/aura/mus/window_tree_host_mus_delegate.h2
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_win.cc16
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_win.h3
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_win_interactive_test.cc65
-rw-r--r--chromium/ui/aura/test/ui_controls_factory_ozone.cc192
-rw-r--r--chromium/ui/aura/window.cc30
-rw-r--r--chromium/ui/aura/window.h7
-rw-r--r--chromium/ui/aura/window_delegate.h5
-rw-r--r--chromium/ui/aura/window_event_dispatcher.cc6
-rw-r--r--chromium/ui/aura/window_event_dispatcher_unittest.cc7
-rw-r--r--chromium/ui/aura/window_observer.h3
-rw-r--r--chromium/ui/aura/window_occlusion_change_builder.cc67
-rw-r--r--chromium/ui/aura/window_occlusion_change_builder.h36
-rw-r--r--chromium/ui/aura/window_occlusion_change_builder_unittest.cc170
-rw-r--r--chromium/ui/aura/window_occlusion_tracker.cc49
-rw-r--r--chromium/ui/aura/window_occlusion_tracker.h19
-rw-r--r--chromium/ui/aura/window_port.cc2
-rw-r--r--chromium/ui/aura/window_port.h3
-rw-r--r--chromium/ui/aura/window_targeter.cc29
-rw-r--r--chromium/ui/aura/window_tree_host.cc37
-rw-r--r--chromium/ui/aura/window_tree_host.h14
-rw-r--r--chromium/ui/aura/window_tree_host_platform.cc2
-rw-r--r--chromium/ui/aura/window_unittest.cc5
-rw-r--r--chromium/ui/aura_extra/BUILD.gn33
-rw-r--r--chromium/ui/aura_extra/image_window_delegate.cc3
-rw-r--r--chromium/ui/aura_extra/image_window_delegate.h2
-rw-r--r--chromium/ui/aura_extra/window_position_in_root_monitor.cc71
-rw-r--r--chromium/ui/aura_extra/window_position_in_root_monitor.h49
-rw-r--r--chromium/ui/aura_extra/window_position_in_root_monitor_unittest.cc74
-rw-r--r--chromium/ui/base/BUILD.gn188
-rw-r--r--chromium/ui/base/accelerators/accelerator_manager_unittest.cc8
-rw-r--r--chromium/ui/base/accelerators/global_media_keys_listener_win.cc84
-rw-r--r--chromium/ui/base/accelerators/global_media_keys_listener_win.h52
-rw-r--r--chromium/ui/base/accelerators/global_media_keys_listener_win_interactive_test.cc152
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener.cc6
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener.h32
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener_mac.mm70
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener_win.cc26
-rw-r--r--chromium/ui/base/accelerators/menu_label_accelerator_util_linux_unittest.cc6
-rw-r--r--chromium/ui/base/accelerators/mojo/BUILD.gn2
-rw-r--r--chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h2
-rw-r--r--chromium/ui/base/accelerators/mojo/typemaps.gni (renamed from chromium/ui/webui/resources/cr_elements/cr_input/compiled_resources2.gyp)10
-rw-r--r--chromium/ui/base/clipboard/BUILD.gn165
-rw-r--r--chromium/ui/base/clipboard/clipboard.cc8
-rw-r--r--chromium/ui/base/clipboard/clipboard.h127
-rw-r--r--chromium/ui/base/clipboard/clipboard_android.cc163
-rw-r--r--chromium/ui/base/clipboard/clipboard_android.h15
-rw-r--r--chromium/ui/base/clipboard/clipboard_aura.cc150
-rw-r--r--chromium/ui/base/clipboard/clipboard_aura.h7
-rw-r--r--chromium/ui/base/clipboard/clipboard_aurax11.cc165
-rw-r--r--chromium/ui/base/clipboard/clipboard_aurax11.h7
-rw-r--r--chromium/ui/base/clipboard/clipboard_constants.cc23
-rw-r--r--chromium/ui/base/clipboard/clipboard_constants.h45
-rw-r--r--chromium/ui/base/clipboard/clipboard_constants_mac.mm (renamed from chromium/ui/base/clipboard/custom_data_helper_mac.mm)4
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type.h118
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_android.cc119
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_aura.cc130
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_mac.mm144
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_win.cc214
-rw-r--r--chromium/ui/base/clipboard/clipboard_mac.h11
-rw-r--r--chromium/ui/base/clipboard/clipboard_mac.mm148
-rw-r--r--chromium/ui/base/clipboard/clipboard_monitor.h4
-rw-r--r--chromium/ui/base/clipboard/clipboard_observer.h4
-rw-r--r--chromium/ui/base/clipboard/clipboard_test_template.h117
-rw-r--r--chromium/ui/base/clipboard/clipboard_unittest.cc27
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_mac.h8
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_mac.mm100
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_win.cc82
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_win.h5
-rw-r--r--chromium/ui/base/clipboard/clipboard_win.cc239
-rw-r--r--chromium/ui/base/clipboard/clipboard_win.h7
-rw-r--r--chromium/ui/base/clipboard/custom_data_helper.h39
-rw-r--r--chromium/ui/base/clipboard/scoped_clipboard_writer.cc9
-rw-r--r--chromium/ui/base/clipboard/scoped_clipboard_writer.h6
-rw-r--r--chromium/ui/base/cocoa/constrained_window/constrained_window_animation.mm4
-rw-r--r--chromium/ui/base/cocoa/menu_controller_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/remote_accessibility_api.mm2
-rw-r--r--chromium/ui/base/cocoa/remote_views_window.h25
-rw-r--r--chromium/ui/base/cocoa/remote_views_window.mm45
-rw-r--r--chromium/ui/base/cocoa/views_hostable.h24
-rw-r--r--chromium/ui/base/cursor/cursor.cc19
-rw-r--r--chromium/ui/base/cursor/cursor.h12
-rw-r--r--chromium/ui/base/cursor/cursor_data.cc93
-rw-r--r--chromium/ui/base/cursor/cursor_data.h105
-rw-r--r--chromium/ui/base/cursor/cursor_util.cc19
-rw-r--r--chromium/ui/base/cursor/cursor_util_unittest.cc (renamed from chromium/ui/base/cursor/cursor_loader_x11_unittest.cc)40
-rw-r--r--chromium/ui/base/cursor/cursors_aura.cc12
-rw-r--r--chromium/ui/base/cursor/image_cursors.cc6
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data.cc10
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data.h16
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc9
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h11
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc33
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h9
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc4
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h6
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm8
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc42
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.h6
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_unittest.cc5
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc4
-rw-r--r--chromium/ui/base/emoji/emoji_panel_helper_chromeos.cc6
-rw-r--r--chromium/ui/base/emoji/emoji_panel_helper_mac.mm3
-rw-r--r--chromium/ui/base/emoji/emoji_panel_helper_win.cc9
-rw-r--r--chromium/ui/base/idle/idle.cc27
-rw-r--r--chromium/ui/base/idle/idle.h15
-rw-r--r--chromium/ui/base/idle/idle_android.cc29
-rw-r--r--chromium/ui/base/idle/idle_chromeos.cc4
-rw-r--r--chromium/ui/base/idle/idle_fuchsia.cc4
-rw-r--r--chromium/ui/base/idle/idle_linux.cc7
-rw-r--r--chromium/ui/base/idle/idle_mac.mm4
-rw-r--r--chromium/ui/base/idle/idle_win.cc4
-rw-r--r--chromium/ui/base/ime/BUILD.gn6
-rw-r--r--chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn7
-rw-r--r--chromium/ui/base/ime/composition_text_util_pango_unittest.cc4
-rw-r--r--chromium/ui/base/ime/dummy_text_input_client.cc5
-rw-r--r--chromium/ui/base/ime/dummy_text_input_client.h8
-rw-r--r--chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc71
-rw-r--r--chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h30
-rw-r--r--chromium/ui/base/ime/ime_bridge.cc43
-rw-r--r--chromium/ui/base/ime/ime_bridge.h5
-rw-r--r--chromium/ui/base/ime/ime_bridge_observer.h10
-rw-r--r--chromium/ui/base/ime/ime_engine_handler_interface.h4
-rw-r--r--chromium/ui/base/ime/input_method_auralinux.cc2
-rw-r--r--chromium/ui/base/ime/input_method_auralinux_unittest.cc2
-rw-r--r--chromium/ui/base/ime/input_method_base.cc6
-rw-r--r--chromium/ui/base/ime/input_method_chromeos.cc11
-rw-r--r--chromium/ui/base/ime/input_method_chromeos.h12
-rw-r--r--chromium/ui/base/ime/input_method_chromeos_unittest.cc48
-rw-r--r--chromium/ui/base/ime/input_method_fuchsia.cc58
-rw-r--r--chromium/ui/base/ime/input_method_fuchsia.h39
-rw-r--r--chromium/ui/base/ime/input_method_win_base.cc5
-rw-r--r--chromium/ui/base/ime/linux/fake_input_method_context_factory.cc4
-rw-r--r--chromium/ui/base/ime/linux/fake_input_method_context_factory.h2
-rw-r--r--chromium/ui/base/ime/text_input_client.h34
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.cc3
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store_unittest.cc16
-rw-r--r--chromium/ui/base/l10n/l10n_util.cc4
-rw-r--r--chromium/ui/base/l10n/l10n_util_android.cc2
-rw-r--r--chromium/ui/base/l10n/l10n_util_mac_unittest.mm4
-rw-r--r--chromium/ui/base/l10n/l10n_util_posix.cc4
-rw-r--r--chromium/ui/base/l10n/l10n_util_unittest.cc19
-rw-r--r--chromium/ui/base/material_design/material_design_controller.cc11
-rw-r--r--chromium/ui/base/models/dialog_model.cc12
-rw-r--r--chromium/ui/base/models/dialog_model.h42
-rw-r--r--chromium/ui/base/models/menu_model.h4
-rw-r--r--chromium/ui/base/models/simple_menu_model.cc8
-rw-r--r--chromium/ui/base/models/simple_menu_model.h5
-rw-r--r--chromium/ui/base/mojo/BUILD.gn18
-rw-r--r--chromium/ui/base/mojo/DEPS4
-rw-r--r--chromium/ui/base/mojo/clipboard_client.cc6
-rw-r--r--chromium/ui/base/mojo/clipboard_client.h7
-rw-r--r--chromium/ui/base/mojo/clipboard_host.cc10
-rw-r--r--chromium/ui/base/mojo/cursor.mojom83
-rw-r--r--chromium/ui/base/mojo/cursor.typemap26
-rw-r--r--chromium/ui/base/mojo/cursor_struct_traits.cc345
-rw-r--r--chromium/ui/base/mojo/cursor_struct_traits.h41
-rw-r--r--chromium/ui/base/mojo/cursor_struct_traits_unittest.cc98
-rw-r--r--chromium/ui/base/mojo/typemaps.gni1
-rw-r--r--chromium/ui/base/resource/resource_bundle.cc66
-rw-r--r--chromium/ui/base/resource/resource_bundle.h14
-rw-r--r--chromium/ui/base/resource/resource_bundle_android.cc35
-rw-r--r--chromium/ui/base/resource/resource_bundle_unittest.cc34
-rw-r--r--chromium/ui/base/resource/scale_factor.cc4
-rw-r--r--chromium/ui/base/template_expressions.cc3
-rw-r--r--chromium/ui/base/text/bytes_formatting.cc4
-rw-r--r--chromium/ui/base/text/bytes_formatting_unittest.cc6
-rw-r--r--chromium/ui/base/ui_base_features.cc29
-rw-r--r--chromium/ui/base/ui_base_features.h10
-rw-r--r--chromium/ui/base/ui_base_switches.cc3
-rw-r--r--chromium/ui/base/ui_base_switches.h1
-rw-r--r--chromium/ui/base/x/selection_owner.cc29
-rw-r--r--chromium/ui/base/x/selection_owner.h6
-rw-r--r--chromium/ui/base/x/selection_requestor.cc32
-rw-r--r--chromium/ui/base/x/selection_requestor_unittest.cc4
-rw-r--r--chromium/ui/base/x/selection_utils.cc26
-rw-r--r--chromium/ui/base/x/selection_utils.h7
-rw-r--r--chromium/ui/base/x/x11_display_util.cc4
-rw-r--r--chromium/ui/base/x/x11_util.cc28
-rw-r--r--chromium/ui/chromeos/BUILD.gn6
-rw-r--r--chromium/ui/compositor/BUILD.gn2
-rw-r--r--chromium/ui/compositor/clip_recorder.cc6
-rw-r--r--chromium/ui/compositor/clip_recorder.h10
-rw-r--r--chromium/ui/compositor/compositing_recorder.cc37
-rw-r--r--chromium/ui/compositor/compositing_recorder.h44
-rw-r--r--chromium/ui/compositor/compositor.cc83
-rw-r--r--chromium/ui/compositor/compositor.h36
-rw-r--r--chromium/ui/compositor/compositor_observer.h22
-rw-r--r--chromium/ui/compositor/compositor_switches.cc3
-rw-r--r--chromium/ui/compositor/compositor_switches.h1
-rw-r--r--chromium/ui/compositor/compositor_unittest.cc9
-rw-r--r--chromium/ui/compositor/host/host_context_factory_private.cc23
-rw-r--r--chromium/ui/compositor/host/host_context_factory_private.h27
-rw-r--r--chromium/ui/compositor/layer.cc37
-rw-r--r--chromium/ui/compositor/layer.h6
-rw-r--r--chromium/ui/compositor/layer_animator.cc21
-rw-r--r--chromium/ui/compositor/layer_animator.h3
-rw-r--r--chromium/ui/compositor/layer_owner_unittest.cc1
-rw-r--r--chromium/ui/compositor/layer_unittest.cc321
-rw-r--r--chromium/ui/compositor/paint_context.h2
-rw-r--r--chromium/ui/compositor/recyclable_compositor_mac.cc1
-rw-r--r--chromium/ui/compositor/recyclable_compositor_mac.h5
-rw-r--r--chromium/ui/compositor/test/test_compositor_host_ozone.cc6
-rw-r--r--chromium/ui/display/mac/screen_mac.mm4
-rw-r--r--chromium/ui/display/manager/configure_displays_task_unittest.cc10
-rw-r--r--chromium/ui/display/manager/display_change_observer.cc24
-rw-r--r--chromium/ui/display/manager/display_change_observer.h2
-rw-r--r--chromium/ui/display/manager/display_configurator_unittest.cc6
-rw-r--r--chromium/ui/display/manager/display_manager.cc14
-rw-r--r--chromium/ui/display/manager/display_manager.h3
-rw-r--r--chromium/ui/display/manager/touch_device_manager.cc11
-rw-r--r--chromium/ui/display/manager/touch_transform_controller.cc5
-rw-r--r--chromium/ui/display/manager/touch_transform_controller.h8
-rw-r--r--chromium/ui/display/manager/touch_transform_controller_unittest.cc2
-rw-r--r--chromium/ui/display/util/display_util.cc4
-rw-r--r--chromium/ui/display/util/edid_parser_unittest.cc20
-rw-r--r--chromium/ui/display/win/screen_win.cc26
-rw-r--r--chromium/ui/events/BUILD.gn4
-rw-r--r--chromium/ui/events/blink/OWNERS2
-rw-r--r--chromium/ui/events/blink/blink_event_util.cc19
-rw-r--r--chromium/ui/events/blink/blink_event_util_unittest.cc50
-rw-r--r--chromium/ui/events/blink/compositor_thread_event_queue.cc5
-rw-r--r--chromium/ui/events/blink/input_handler_proxy.cc37
-rw-r--r--chromium/ui/events/blink/input_handler_proxy.h1
-rw-r--r--chromium/ui/events/blink/input_handler_proxy_unittest.cc65
-rw-r--r--chromium/ui/events/blink/web_input_event.cc8
-rw-r--r--chromium/ui/events/blink/web_input_event_unittest.cc8
-rw-r--r--chromium/ui/events/devices/device_data_manager.cc20
-rw-r--r--chromium/ui/events/devices/input_device_event_observer.h17
-rw-r--r--chromium/ui/events/devices/input_device_observer_android.cc25
-rw-r--r--chromium/ui/events/devices/input_device_observer_android.h4
-rw-r--r--chromium/ui/events/devices/input_device_observer_win.cc28
-rw-r--r--chromium/ui/events/devices/x11/device_data_manager_x11.cc9
-rw-r--r--chromium/ui/events/devices/x11/device_data_manager_x11_unittest.cc2
-rw-r--r--chromium/ui/events/event.cc4
-rw-r--r--chromium/ui/events/event.h3
-rw-r--r--chromium/ui/events/event_constants.h11
-rw-r--r--chromium/ui/events/event_dispatcher.h10
-rw-r--r--chromium/ui/events/event_processor_unittest.cc6
-rw-r--r--chromium/ui/events/event_source.cc16
-rw-r--r--chromium/ui/events/event_source.h8
-rw-r--r--chromium/ui/events/event_unittest.cc4
-rw-r--r--chromium/ui/events/keycodes/BUILD.gn2
-rw-r--r--chromium/ui/events/keycodes/DEPS2
-rw-r--r--chromium/ui/events/keycodes/dom/dom_key.h13
-rw-r--r--chromium/ui/events/keycodes/dom/keycode_converter.cc5
-rw-r--r--chromium/ui/events/keycodes/dom/keycode_converter_unittest.cc3
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion.cc12
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion.h5
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm6
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_x.cc20
-rw-r--r--chromium/ui/events/keycodes/keysym_to_unicode.cc9
-rw-r--r--chromium/ui/events/keycodes/platform_key_map_win.cc70
-rw-r--r--chromium/ui/events/keycodes/platform_key_map_win.h3
-rw-r--r--chromium/ui/events/keycodes/xkb_keysym.h2
-rw-r--r--chromium/ui/events/mojo/event.mojom45
-rw-r--r--chromium/ui/events/mojo/event.typemap1
-rw-r--r--chromium/ui/events/mojo/event_constants.mojom14
-rw-r--r--chromium/ui/events/mojo/event_struct_traits.cc83
-rw-r--r--chromium/ui/events/mojo/event_struct_traits.h33
-rw-r--r--chromium/ui/events/mojo/struct_traits_unittest.cc86
-rw-r--r--chromium/ui/events/ozone/device/udev/device_manager_udev.cc6
-rwxr-xr-xchromium/ui/events/ozone/evdev/capture_device_capabilities.py2
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc42
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info.cc38
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_test_util.cc128
-rw-r--r--chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc6
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc4
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc13
-rw-r--r--chromium/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc35
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc55
-rw-r--r--chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder_unittest.cc22
-rw-r--r--chromium/ui/events/ozone/evdev/touch_filter/far_apart_taps_touch_noise_filter.cc6
-rw-r--r--chromium/ui/events/ozone/gamepad/static_gamepad_mapping.cc10
-rw-r--r--chromium/ui/events/ozone/layout/keyboard_layout_engine_manager.cc2
-rw-r--r--chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc126
-rw-r--r--chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h1
-rw-r--r--chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc10
-rw-r--r--chromium/ui/events/platform/platform_event_source.cc10
-rw-r--r--chromium/ui/events/platform/platform_event_source.h12
-rw-r--r--chromium/ui/events/platform/platform_event_source_unittest.cc12
-rw-r--r--chromium/ui/events/win/keyboard_hook_win_base.cc1
-rw-r--r--chromium/ui/events/win/media_keyboard_hook_win_unittest.cc2
-rw-r--r--chromium/ui/events/win/modifier_keyboard_hook_win_unittest.cc2
-rw-r--r--chromium/ui/events/x/events_x.cc4
-rw-r--r--chromium/ui/events/x/events_x_unittest.cc6
-rw-r--r--chromium/ui/file_manager/BUILD.gn1
-rw-r--r--chromium/ui/file_manager/audio_player/js/BUILD.gn2
-rw-r--r--chromium/ui/file_manager/base/js/BUILD.gn3
-rw-r--r--chromium/ui/file_manager/file_manager/background/js/BUILD.gn52
-rw-r--r--chromium/ui/file_manager/file_manager/common/js/BUILD.gn10
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/elements/BUILD.gn25
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn89
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn76
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn54
-rw-r--r--chromium/ui/file_manager/file_manager/test/BUILD.gn9
-rw-r--r--chromium/ui/file_manager/video_player/js/BUILD.gn8
-rw-r--r--chromium/ui/file_manager/video_player/js/cast/BUILD.gn1
-rw-r--r--chromium/ui/gfx/BUILD.gn17
-rw-r--r--chromium/ui/gfx/DEPS2
-rw-r--r--chromium/ui/gfx/OWNERS4
-rw-r--r--chromium/ui/gfx/animation/animation.cc6
-rw-r--r--chromium/ui/gfx/animation/animation.h4
-rw-r--r--chromium/ui/gfx/animation/animation_mac.mm25
-rw-r--r--chromium/ui/gfx/animation/animation_win.cc9
-rw-r--r--chromium/ui/gfx/animation/slide_animation.cc10
-rw-r--r--chromium/ui/gfx/break_list_unittest.cc5
-rw-r--r--chromium/ui/gfx/buffer_format_util.cc15
-rw-r--r--chromium/ui/gfx/canvas.cc4
-rw-r--r--chromium/ui/gfx/canvas_skia.cc9
-rw-r--r--chromium/ui/gfx/codec/chromeos/jpeg_codec_robust_slow_unittest.cc6
-rw-r--r--chromium/ui/gfx/codec/jpeg_codec_unittest.cc7
-rw-r--r--chromium/ui/gfx/codec/png_codec_unittest.cc8
-rw-r--r--chromium/ui/gfx/color_analysis.cc16
-rw-r--r--chromium/ui/gfx/color_palette.h32
-rw-r--r--chromium/ui/gfx/color_space.cc279
-rw-r--r--chromium/ui/gfx/color_space.h10
-rw-r--r--chromium/ui/gfx/color_space_unittest.cc43
-rw-r--r--chromium/ui/gfx/color_space_win.cc5
-rw-r--r--chromium/ui/gfx/color_transform_unittest.cc4
-rw-r--r--chromium/ui/gfx/color_utils.cc128
-rw-r--r--chromium/ui/gfx/color_utils.h42
-rw-r--r--chromium/ui/gfx/color_utils_unittest.cc71
-rw-r--r--chromium/ui/gfx/font_fallback_mac.mm6
-rw-r--r--chromium/ui/gfx/font_fallback_win.cc8
-rw-r--r--chromium/ui/gfx/gdi_util.h1
-rw-r--r--chromium/ui/gfx/generic_shared_memory_id.h7
-rw-r--r--chromium/ui/gfx/geometry/point.cc4
-rw-r--r--chromium/ui/gfx/geometry/point.h6
-rw-r--r--chromium/ui/gfx/geometry/point3_unittest.cc4
-rw-r--r--chromium/ui/gfx/geometry/point_unittest.cc4
-rw-r--r--chromium/ui/gfx/geometry/quad_unittest.cc4
-rw-r--r--chromium/ui/gfx/geometry/quaternion_unittest.cc8
-rw-r--r--chromium/ui/gfx/geometry/rect.cc4
-rw-r--r--chromium/ui/gfx/geometry/rect.h6
-rw-r--r--chromium/ui/gfx/geometry/rect_f.cc2
-rw-r--r--chromium/ui/gfx/geometry/rect_f.h4
-rw-r--r--chromium/ui/gfx/geometry/scroll_offset_unittest.cc10
-rw-r--r--chromium/ui/gfx/geometry/size.cc4
-rw-r--r--chromium/ui/gfx/geometry/size.h8
-rw-r--r--chromium/ui/gfx/geometry/vector2d_unittest.cc18
-rw-r--r--chromium/ui/gfx/geometry/vector3d_f.cc7
-rw-r--r--chromium/ui/gfx/geometry/vector3d_unittest.cc42
-rw-r--r--chromium/ui/gfx/half_float_unittest.cc4
-rw-r--r--chromium/ui/gfx/harfbuzz_font_skia.cc35
-rw-r--r--chromium/ui/gfx/icc_profile.cc2
-rw-r--r--chromium/ui/gfx/icc_profile.h2
-rw-r--r--chromium/ui/gfx/icon_util.cc35
-rw-r--r--chromium/ui/gfx/icon_util.h4
-rw-r--r--chromium/ui/gfx/image/image.cc4
-rw-r--r--chromium/ui/gfx/image/image.h4
-rw-r--r--chromium/ui/gfx/image/image_ios_unittest.mm6
-rw-r--r--chromium/ui/gfx/ios/uikit_util_unittest.mm6
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc11
-rw-r--r--chromium/ui/gfx/mac/io_surface.cc4
-rw-r--r--chromium/ui/gfx/mojo/BUILD.gn1
-rw-r--r--chromium/ui/gfx/mojo/rrect_f.mojom26
-rw-r--r--chromium/ui/gfx/mojo/rrect_f.typemap11
-rw-r--r--chromium/ui/gfx/mojo/rrect_f_struct_traits.h112
-rw-r--r--chromium/ui/gfx/mojo/struct_traits_unittest.cc37
-rw-r--r--chromium/ui/gfx/mojo/traits_test_service.mojom4
-rw-r--r--chromium/ui/gfx/native_widget_types.h4
-rw-r--r--chromium/ui/gfx/nine_image_painter.cc10
-rw-r--r--chromium/ui/gfx/paint_throbber.cc67
-rw-r--r--chromium/ui/gfx/paint_throbber.h20
-rw-r--r--chromium/ui/gfx/paint_vector_icon.cc5
-rw-r--r--chromium/ui/gfx/paint_vector_icon_unittest.cc15
-rw-r--r--chromium/ui/gfx/path.cc16
-rw-r--r--chromium/ui/gfx/path.h27
-rw-r--r--chromium/ui/gfx/path_mac.mm5
-rw-r--r--chromium/ui/gfx/path_mac_unittest.mm11
-rw-r--r--chromium/ui/gfx/path_win.cc2
-rw-r--r--chromium/ui/gfx/path_win_unittest.cc18
-rw-r--r--chromium/ui/gfx/path_x11.cc2
-rw-r--r--chromium/ui/gfx/platform_font_mac_unittest.mm4
-rw-r--r--chromium/ui/gfx/platform_font_skia.cc20
-rw-r--r--chromium/ui/gfx/platform_font_win.cc31
-rw-r--r--chromium/ui/gfx/render_text.cc109
-rw-r--r--chromium/ui/gfx/render_text.h24
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.cc41
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.h3
-rw-r--r--chromium/ui/gfx/render_text_mac.h3
-rw-r--r--chromium/ui/gfx/render_text_mac.mm14
-rw-r--r--chromium/ui/gfx/render_text_test_api.h6
-rw-r--r--chromium/ui/gfx/render_text_unittest.cc184
-rw-r--r--chromium/ui/gfx/rrect_f.cc121
-rw-r--r--chromium/ui/gfx/rrect_f.h153
-rw-r--r--chromium/ui/gfx/rrect_f_unittest.cc232
-rw-r--r--chromium/ui/gfx/sequential_id_generator.h4
-rw-r--r--chromium/ui/gfx/shadow_value_unittest.cc4
-rw-r--r--chromium/ui/gfx/skbitmap_operations.cc4
-rw-r--r--chromium/ui/gfx/skia_util.cc33
-rw-r--r--chromium/ui/gfx/skia_util.h11
-rw-r--r--chromium/ui/gfx/sys_color_change_listener.cc14
-rw-r--r--chromium/ui/gfx/text_constants.h11
-rw-r--r--chromium/ui/gfx/text_elider.cc51
-rw-r--r--chromium/ui/gfx/text_elider_unittest.cc162
-rw-r--r--chromium/ui/gfx/text_utils.cc87
-rw-r--r--chromium/ui/gfx/text_utils.h10
-rw-r--r--chromium/ui/gfx/text_utils_unittest.cc266
-rw-r--r--chromium/ui/gfx/transform_unittest.cc36
-rw-r--r--chromium/ui/gfx/typemaps.gni1
-rw-r--r--chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc96
-rw-r--r--chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.h50
-rw-r--r--chromium/ui/gfx/win/singleton_hwnd_observer.h2
-rw-r--r--chromium/ui/gfx/x/x11_atom_cache.cc3
-rw-r--r--chromium/ui/gl/BUILD.gn52
-rw-r--r--chromium/ui/gl/OWNERS2
-rw-r--r--chromium/ui/gl/android/android_surface_control_compat.cc210
-rw-r--r--chromium/ui/gl/android/android_surface_control_compat.h19
-rw-r--r--chromium/ui/gl/angle_platform_impl.cc5
-rw-r--r--chromium/ui/gl/dc_renderer_layer_params.cc29
-rw-r--r--chromium/ui/gl/dc_renderer_layer_params.h74
-rwxr-xr-xchromium/ui/gl/generate_bindings.py2
-rw-r--r--chromium/ui/gl/gl_api_unittest.cc14
-rw-r--r--chromium/ui/gl/gl_bindings.h7
-rw-r--r--chromium/ui/gl/gl_bindings_api_autogen_gl.h6
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_gl.cc35
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_gl.h8
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_mock.cc4
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_mock.h2
-rw-r--r--chromium/ui/gl/gl_context.cc1
-rw-r--r--chromium/ui/gl/gl_image.cc18
-rw-r--r--chromium/ui/gl/gl_image.h26
-rw-r--r--chromium/ui/gl/gl_image_ahardwarebuffer.cc35
-rw-r--r--chromium/ui/gl/gl_image_ahardwarebuffer.h12
-rw-r--r--chromium/ui/gl/gl_image_dxgi.cc222
-rw-r--r--chromium/ui/gl/gl_image_dxgi.h82
-rw-r--r--chromium/ui/gl/gl_image_dxgi_unittest.cc6
-rw-r--r--chromium/ui/gl/gl_image_io_surface.mm2
-rw-r--r--chromium/ui/gl/gl_image_io_surface_unittest.cc3
-rw-r--r--chromium/ui/gl/gl_image_native_pixmap.cc184
-rw-r--r--chromium/ui/gl/gl_image_native_pixmap.h10
-rw-r--r--chromium/ui/gl/gl_image_native_pixmap_unittest.cc3
-rw-r--r--chromium/ui/gl/gl_image_shared_memory.cc5
-rw-r--r--chromium/ui/gl/gl_implementation.cc7
-rw-r--r--chromium/ui/gl/gl_mock_autogen_gl.h4
-rw-r--r--chromium/ui/gl/gl_stub_autogen_gl.cc6
-rw-r--r--chromium/ui/gl/gl_stub_autogen_gl.h6
-rw-r--r--chromium/ui/gl/gl_surface_egl.cc23
-rw-r--r--chromium/ui/gl/gl_surface_egl_surface_control.cc56
-rw-r--r--chromium/ui/gl/gl_surface_egl_surface_control.h16
-rw-r--r--chromium/ui/gl/gl_switches.cc5
-rw-r--r--chromium/ui/gl/init/BUILD.gn2
-rw-r--r--chromium/ui/gl/init/create_gr_gl_interface.cc5
-rw-r--r--chromium/ui/gl/init/gl_factory_mac.cc2
-rw-r--r--chromium/ui/gl/init/gl_initializer_android.cc2
-rw-r--r--chromium/ui/gl/init/gl_initializer_mac.cc2
-rw-r--r--chromium/ui/gl/init/gl_initializer_win.cc2
-rw-r--r--chromium/ui/gl/init/gl_initializer_x11.cc2
-rw-r--r--chromium/ui/keyboard/BUILD.gn7
-rw-r--r--chromium/ui/keyboard/DEPS1
-rw-r--r--chromium/ui/keyboard/keyboard_controller.cc70
-rw-r--r--chromium/ui/keyboard/keyboard_controller.h35
-rw-r--r--chromium/ui/keyboard/keyboard_controller_unittest.cc34
-rw-r--r--chromium/ui/keyboard/keyboard_layout_delegate.h15
-rw-r--r--chromium/ui/keyboard/keyboard_layout_manager.cc8
-rw-r--r--chromium/ui/keyboard/keyboard_ui.cc8
-rw-r--r--chromium/ui/keyboard/keyboard_ui.h11
-rw-r--r--chromium/ui/keyboard/keyboard_ui_factory.cc12
-rw-r--r--chromium/ui/keyboard/keyboard_ui_factory.h32
-rw-r--r--chromium/ui/keyboard/keyboard_util_unittest.cc20
-rw-r--r--chromium/ui/keyboard/resources/keyboard_resource_util.cc4
-rw-r--r--chromium/ui/latency/histograms.h4
-rw-r--r--chromium/ui/latency/latency_tracker.cc34
-rw-r--r--chromium/ui/login/display_manager.js47
-rw-r--r--chromium/ui/login/md_screen_container.css2
-rw-r--r--chromium/ui/login/screen_container.css2
-rw-r--r--chromium/ui/message_center/BUILD.gn17
-rw-r--r--chromium/ui/message_center/fake_message_center.cc6
-rw-r--r--chromium/ui/message_center/fake_message_center.h3
-rw-r--r--chromium/ui/message_center/message_center.h5
-rw-r--r--chromium/ui/message_center/message_center_impl.cc11
-rw-r--r--chromium/ui/message_center/message_center_impl.h3
-rw-r--r--chromium/ui/message_center/notification_list.cc10
-rw-r--r--chromium/ui/message_center/notification_list.h5
-rw-r--r--chromium/ui/message_center/public/cpp/notification.h3
-rw-r--r--chromium/ui/message_center/public/mojo/notification.mojom3
-rw-r--r--chromium/ui/message_center/public/mojo/notification_struct_traits.cc10
-rw-r--r--chromium/ui/message_center/public/mojo/notification_struct_traits.h1
-rw-r--r--chromium/ui/message_center/vector_icons/notification_snooze_button.icon6
-rw-r--r--chromium/ui/message_center/views/message_view.cc36
-rw-r--r--chromium/ui/message_center/views/message_view.h8
-rw-r--r--chromium/ui/message_center/views/message_view_factory.cc24
-rw-r--r--chromium/ui/message_center/views/notification_control_buttons_view.cc21
-rw-r--r--chromium/ui/message_center/views/notification_control_buttons_view.h15
-rw-r--r--chromium/ui/message_center/views/notification_header_view.cc68
-rw-r--r--chromium/ui/message_center/views/notification_header_view.h4
-rw-r--r--chromium/ui/message_center/views/notification_view.cc65
-rw-r--r--chromium/ui/message_center/views/notification_view.h1
-rw-r--r--chromium/ui/message_center/views/notification_view_md.cc85
-rw-r--r--chromium/ui/message_center/views/notification_view_md.h15
-rw-r--r--chromium/ui/message_center/views/notification_view_md_unittest.cc11
-rw-r--r--chromium/ui/message_center/views/notification_view_unittest.cc12
-rw-r--r--chromium/ui/native_theme/BUILD.gn21
-rw-r--r--chromium/ui/native_theme/OWNERS1
-rw-r--r--chromium/ui/native_theme/caption_style.cc32
-rw-r--r--chromium/ui/native_theme/caption_style.h34
-rw-r--r--chromium/ui/native_theme/common_theme.cc94
-rw-r--r--chromium/ui/native_theme/native_theme.cc8
-rw-r--r--chromium/ui/native_theme/native_theme.h8
-rw-r--r--chromium/ui/native_theme/native_theme_aura.cc4
-rw-r--r--chromium/ui/native_theme/native_theme_dark_aura.cc5
-rw-r--r--chromium/ui/native_theme/native_theme_mac.h14
-rw-r--r--chromium/ui/native_theme/native_theme_mac.mm111
-rw-r--r--chromium/ui/native_theme/native_theme_win.cc47
-rw-r--r--chromium/ui/native_theme/native_theme_win.h7
-rw-r--r--chromium/ui/native_theme/test_native_theme.cc48
-rw-r--r--chromium/ui/native_theme/test_native_theme.h44
-rw-r--r--chromium/ui/ozone/BUILD.gn12
-rw-r--r--chromium/ui/ozone/common/BUILD.gn5
-rw-r--r--chromium/ui/ozone/common/egl_util.cc2
-rw-r--r--chromium/ui/ozone/common/linux/BUILD.gn1
-rw-r--r--chromium/ui/ozone/demo/BUILD.gn2
-rw-r--r--chromium/ui/ozone/demo/skia/skia_gl_renderer.cc10
-rw-r--r--chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc13
-rw-r--r--chromium/ui/ozone/demo/surfaceless_gl_renderer.cc5
-rw-r--r--chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc5
-rw-r--r--chromium/ui/ozone/ozone.gni11
-rw-r--r--chromium/ui/ozone/platform/drm/DEPS2
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc24
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.h1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc12
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc12
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h4
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc17
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc35
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc12
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_device_handle.cc11
-rw-r--r--chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc2
-rw-r--r--chromium/ui/ozone/platform/scenic/BUILD.gn16
-rw-r--r--chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc17
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc14
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_gpu_host.h7
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc5
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_gpu_service.h5
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface.cc66
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface.h72
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc115
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.h60
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.cc30
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.h14
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc29
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window_canvas.h14
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc129
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h12
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_magma.h159
-rw-r--r--chromium/ui/ozone/platform/wayland/BUILD.gn5
-rw-r--r--chromium/ui/ozone/platform/wayland/DEPS2
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc10
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc8
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_connection.cc26
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_connection.h21
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_data_device_unittest.cc16
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_data_source.cc6
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_data_source.h8
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_keyboard.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_object.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_output.cc15
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_output_manager.cc11
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_output_manager.h4
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_pointer.cc1
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_screen.cc17
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_screen.h6
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_screen_unittest.cc107
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_test.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_touch.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_window.cc12
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_window.h2
-rw-r--r--chromium/ui/ozone/public/ozone_platform.cc14
-rw-r--r--chromium/ui/ozone/public/ozone_platform.h4
-rw-r--r--chromium/ui/ozone/public/platform_clipboard.h (renamed from chromium/ui/ozone/public/clipboard_delegate.h)10
-rw-r--r--chromium/ui/ozone/public/platform_window_surface.h40
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.cc7
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.h6
-rw-r--r--chromium/ui/ozone/public/surface_ozone_canvas.h10
-rw-r--r--chromium/ui/platform_window/BUILD.gn2
-rw-r--r--chromium/ui/resources/default_100_percent/common/emoji_menu_item.pngbin496 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/mac/menu_hierarchy_arrow.pngbin127 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/supervised_illustration_done.pngbin5042 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/supervised_illustration_start.pngbin22567 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/emoji_menu_item.pngbin1051 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/mac/menu_hierarchy_arrow.pngbin176 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/supervised_illustration_done.pngbin11582 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/supervised_illustration_start.pngbin46090 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_300_percent/common/emoji_menu_item.pngbin1554 -> 0 bytes
-rw-r--r--chromium/ui/resources/ui_resources.grd1
-rw-r--r--chromium/ui/shell_dialogs/BUILD.gn1
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog.h7
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_mac.mm9
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm4
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_unittest.cc4
-rw-r--r--chromium/ui/shell_dialogs/selected_file_info.cc8
-rw-r--r--chromium/ui/shell_dialogs/selected_file_info.h12
-rw-r--r--chromium/ui/strings/translations/ui_strings_am.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ar.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_bg.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_bn.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ca.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_cs.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_da.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_de.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_el.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_en-GB.xtb7
-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.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_fa.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_fi.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_fil.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_fr.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_gu.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_hi.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_hr.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_hu.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_id.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_it.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_iw.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ja.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_kn.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ko.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_lt.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_lv.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ml.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_mr.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ms.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_nl.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_no.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_pl.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-BR.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-PT.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ro.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ru.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_sk.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_sl.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_sr.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_sv.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_sw.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ta.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_te.xtb9
-rw-r--r--chromium/ui/strings/translations/ui_strings_th.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_tr.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_uk.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_vi.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-CN.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-TW.xtb7
-rw-r--r--chromium/ui/strings/ui_strings.grd21
-rw-r--r--chromium/ui/views/BUILD.gn282
-rw-r--r--chromium/ui/views/DEPS12
-rw-r--r--chromium/ui/views/OWNERS5
-rw-r--r--chromium/ui/views/accessibility/accessibility_alert_window.cc50
-rw-r--r--chromium/ui/views/accessibility/accessibility_alert_window.h50
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.cc29
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.h16
-rw-r--r--chromium/ui/views/accessibility/ax_aura_window_utils.cc49
-rw-r--r--chromium/ui/views/accessibility/ax_aura_window_utils.h43
-rw-r--r--chromium/ui/views/accessibility/ax_aura_window_utils_unittest.cc170
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.cc44
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.h13
-rw-r--r--chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc21
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views.cc27
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views.h13
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views_unittest.cc5
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.cc13
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.h6
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view.cc13
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view.h13
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc26
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.h6
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc109
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.h19
-rw-r--r--chromium/ui/views/accessibility/view_accessibility.cc10
-rw-r--r--chromium/ui/views/accessibility/view_accessibility.h6
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc16
-rw-r--r--chromium/ui/views/accessible_pane_view.h1
-rw-r--r--chromium/ui/views/accessible_pane_view_unittest.cc20
-rw-r--r--chromium/ui/views/animation/bounds_animator.cc6
-rw-r--r--chromium/ui/views/animation/bounds_animator.h5
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.cc51
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.h30
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.cc4
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.h7
-rw-r--r--chromium/ui/views/animation/ink_drop_impl_unittest.cc7
-rw-r--r--chromium/ui/views/animation/ink_drop_mask.h3
-rw-r--r--chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc6
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc89
-rw-r--r--chromium/ui/views/bubble/bubble_border.h4
-rw-r--r--chromium/ui/views/bubble/bubble_border_unittest.cc39
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.cc14
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.h9
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc4
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.cc41
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.h14
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view_unittest.cc43
-rw-r--r--chromium/ui/views/bubble/footnote_container_view.cc8
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host_impl.h62
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm361
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm6
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_unittest.mm38
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm2
-rw-r--r--chromium/ui/views/cocoa/text_input_host.h91
-rw-r--r--chromium/ui/views/cocoa/text_input_host.mm408
-rw-r--r--chromium/ui/views/controls/button/button.cc5
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc28
-rw-r--r--chromium/ui/views/controls/button/checkbox.h1
-rw-r--r--chromium/ui/views/controls/button/image_button.cc1
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.cc15
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.h12
-rw-r--r--chromium/ui/views/controls/button/label_button.cc44
-rw-r--r--chromium/ui/views/controls/button/label_button.h7
-rw-r--r--chromium/ui/views/controls/button/label_button_border.cc2
-rw-r--r--chromium/ui/views/controls/button/md_text_button.cc76
-rw-r--r--chromium/ui/views/controls/button/md_text_button.h10
-rw-r--r--chromium/ui/views/controls/button/menu_button_unittest.cc15
-rw-r--r--chromium/ui/views/controls/button/radio_button.cc41
-rw-r--r--chromium/ui/views/controls/button/radio_button.h2
-rw-r--r--chromium/ui/views/controls/button/toggle_button.cc18
-rw-r--r--chromium/ui/views/controls/combobox/combobox.cc38
-rw-r--r--chromium/ui/views/controls/combobox/combobox.h23
-rw-r--r--chromium/ui/views/controls/focus_ring.cc42
-rw-r--r--chromium/ui/views/controls/focus_ring.h7
-rw-r--r--chromium/ui/views/controls/focusable_border.cc8
-rw-r--r--chromium/ui/views/controls/label.cc63
-rw-r--r--chromium/ui/views/controls/label.h14
-rw-r--r--chromium/ui/views/controls/label_unittest.cc78
-rw-r--r--chromium/ui/views/controls/link.cc8
-rw-r--r--chromium/ui/views/controls/menu/menu_config.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_config.h3
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc19
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.h13
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc7
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.h11
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc1
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc94
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.h8
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view_unittest.cc40
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc16
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.h1
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc7
-rw-r--r--chromium/ui/views/controls/menu/menu_runner.cc6
-rw-r--r--chromium/ui/views/controls/menu/menu_runner.h8
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl.h13
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl_adapter.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl_adapter.h3
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h12
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm3
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl_interface.h13
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_unittest.cc33
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc27
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.h7
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.cc7
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.h5
-rw-r--r--chromium/ui/views/controls/native/native_view_host.cc8
-rw-r--r--chromium/ui/views/controls/native/native_view_host.h9
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.cc42
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.h8
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura_unittest.cc57
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac.h2
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac.mm92
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac_unittest.mm12
-rw-r--r--chromium/ui/views/controls/native/native_view_host_wrapper.h8
-rw-r--r--chromium/ui/views/controls/prefix_selector.cc4
-rw-r--r--chromium/ui/views/controls/prefix_selector.h4
-rw-r--r--chromium/ui/views/controls/progress_bar.cc6
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc5
-rw-r--r--chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm3
-rw-r--r--chromium/ui/views/controls/scrollbar/scroll_bar_views.cc1
-rw-r--r--chromium/ui/views/controls/styled_label_unittest.cc14
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc7
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm7
-rw-r--r--chromium/ui/views/controls/table/table_header.cc38
-rw-r--r--chromium/ui/views/controls/table/table_header.h6
-rw-r--r--chromium/ui/views/controls/table/table_view.cc502
-rw-r--r--chromium/ui/views/controls/table/table_view.h67
-rw-r--r--chromium/ui/views/controls/table/table_view_unittest.cc287
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc68
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h9
-rw-r--r--chromium/ui/views/controls/textfield/textfield_controller.h4
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model_unittest.cc6
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc70
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_base.cc13
-rw-r--r--chromium/ui/views/controls/webview/web_contents_set_background_color.cc2
-rw-r--r--chromium/ui/views/controls/webview/web_contents_set_background_color.h3
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.cc4
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.h4
-rw-r--r--chromium/ui/views/controls/webview/webview.cc15
-rw-r--r--chromium/ui/views/controls/webview/webview_unittest.cc10
-rw-r--r--chromium/ui/views/corewm/DEPS1
-rw-r--r--chromium/ui/views/corewm/desktop_capture_controller_unittest.cc5
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_unittest.cc67
-rw-r--r--chromium/ui/views/corewm/tooltip_win.cc4
-rw-r--r--chromium/ui/views/event_monitor_unittest.cc14
-rw-r--r--chromium/ui/views/examples/BUILD.gn2
-rw-r--r--chromium/ui/views/examples/OWNERS1
-rw-r--r--chromium/ui/views/examples/bubble_example.cc6
-rw-r--r--chromium/ui/views/examples/examples_main.cc5
-rw-r--r--chromium/ui/views/examples/examples_window.cc2
-rw-r--r--chromium/ui/views/examples/flex_layout_example.cc118
-rw-r--r--chromium/ui/views/examples/flex_layout_example.h58
-rw-r--r--chromium/ui/views/examples/label_example.cc10
-rw-r--r--chromium/ui/views/examples/multiline_example.cc6
-rw-r--r--chromium/ui/views/examples/radio_button_example.cc6
-rw-r--r--chromium/ui/views/examples/text_example.cc14
-rw-r--r--chromium/ui/views/examples/textfield_example.cc6
-rw-r--r--chromium/ui/views/focus/focus_manager_factory.cc19
-rw-r--r--chromium/ui/views/focus/focus_manager_factory.h9
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest.cc97
-rw-r--r--chromium/ui/views/focus/focus_search.cc99
-rw-r--r--chromium/ui/views/focus/focus_search.h19
-rw-r--r--chromium/ui/views/focus/focus_traversal_unittest.cc10
-rw-r--r--chromium/ui/views/interactive_ui_tests_manifest.json (renamed from chromium/ui/views/mus/interactive_ui_tests_manifest.json)4
-rw-r--r--chromium/ui/views/layout/OWNERS1
-rw-r--r--chromium/ui/views/layout/flex_layout.cc1044
-rw-r--r--chromium/ui/views/layout/flex_layout.h174
-rw-r--r--chromium/ui/views/layout/flex_layout_types.cc203
-rw-r--r--chromium/ui/views/layout/flex_layout_types.h164
-rw-r--r--chromium/ui/views/layout/flex_layout_types_internal.cc465
-rw-r--r--chromium/ui/views/layout/flex_layout_types_internal.h367
-rw-r--r--chromium/ui/views/layout/flex_layout_unittest.cc1730
-rw-r--r--chromium/ui/views/layout/grid_layout_unittest.cc7
-rw-r--r--chromium/ui/views/layout/layout_manager.cc9
-rw-r--r--chromium/ui/views/layout/layout_manager.h14
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.h2
-rw-r--r--chromium/ui/views/masked_targeter_delegate.cc4
-rw-r--r--chromium/ui/views/masked_targeter_delegate.h5
-rw-r--r--chromium/ui/views/mus/BUILD.gn213
-rw-r--r--chromium/ui/views/mus/DEPS9
-rw-r--r--chromium/ui/views/mus/OWNERS6
-rw-r--r--chromium/ui/views/mus/ax_remote_host_unittest.cc6
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus.cc5
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus.h2
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus_unittest.cc3
-rw-r--r--chromium/ui/views/mus/clipboard_unittest.cc36
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.cc131
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.h5
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc60
-rw-r--r--chromium/ui/views/mus/drag_interactive_uitest.cc14
-rw-r--r--chromium/ui/views/mus/interactive_ui_tests_mus.cc9
-rw-r--r--chromium/ui/views/mus/mus_client.cc10
-rw-r--r--chromium/ui/views/mus/mus_client.h2
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc8
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider.cc4
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider.h6
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc19
-rw-r--r--chromium/ui/views/mus/run_all_unittests_mus.cc9
-rw-r--r--chromium/ui/views/mus/screen_mus_unittest.cc57
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.cc263
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.h46
-rw-r--r--chromium/ui/views/mus/window_manager_constants_converters.cc2
-rw-r--r--chromium/ui/views/painter.cc45
-rw-r--r--chromium/ui/views/painter.h4
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_close.pngbin197 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_close_hover.pngbin260 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_close_pressed.pngbin210 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_maximize.pngbin170 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_maximize_hover.pngbin217 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_maximize_pressed.pngbin177 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_minimize.pngbin151 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_minimize_hover.pngbin199 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_minimize_pressed.pngbin153 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_restore.pngbin187 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_restore_hover.pngbin237 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/linux/linux_restore_pressed.pngbin198 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/views_resources.grd52
-rw-r--r--chromium/ui/views/round_rect_painter.cc1
-rw-r--r--chromium/ui/views/selection_controller.cc6
-rw-r--r--chromium/ui/views/selection_controller.h5
-rw-r--r--chromium/ui/views/selection_controller_unittest.cc30
-rw-r--r--chromium/ui/views/style/platform_style.cc1
-rw-r--r--chromium/ui/views/style/platform_style.h5
-rw-r--r--chromium/ui/views/style/platform_style_mac.mm3
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc1
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc52
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc16
-rw-r--r--chromium/ui/views/unittests_manifest.json (renamed from chromium/ui/views/mus/unittests_manifest.json)4
-rw-r--r--chromium/ui/views/view.cc167
-rw-r--r--chromium/ui/views/view.h50
-rw-r--r--chromium/ui/views/view_properties.cc1
-rw-r--r--chromium/ui/views/view_properties.h12
-rw-r--r--chromium/ui/views/view_targeter_unittest.cc4
-rw-r--r--chromium/ui/views/view_unittest.cc186
-rw-r--r--chromium/ui/views/view_unittest_aura.cc5
-rw-r--r--chromium/ui/views/views_test_suite.cc19
-rw-r--r--chromium/ui/views/views_test_suite.h6
-rw-r--r--chromium/ui/views/widget/DEPS5
-rw-r--r--chromium/ui/views/widget/ax_native_widget_mac_unittest.mm7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc15
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h11
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc28
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc24
-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.cc83
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc9
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.cc20
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc16
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc33
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc19
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc13
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc14
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc6
-rw-r--r--chromium/ui/views/widget/desktop_widget_unittest.cc17
-rw-r--r--chromium/ui/views/widget/drop_helper.cc2
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc8
-rw-r--r--chromium/ui/views/widget/native_widget_aura.h3
-rw-r--r--chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc9
-rw-r--r--chromium/ui/views/widget/native_widget_aura_unittest.cc4
-rw-r--r--chromium/ui/views/widget/native_widget_delegate.h12
-rw-r--r--chromium/ui/views/widget/native_widget_mac.h36
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm56
-rw-r--r--chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm5
-rw-r--r--chromium/ui/views/widget/native_widget_mac_unittest.mm46
-rw-r--r--chromium/ui/views/widget/native_widget_private.cc5
-rw-r--r--chromium/ui/views/widget/native_widget_private.h4
-rw-r--r--chromium/ui/views/widget/native_widget_unittest.cc4
-rw-r--r--chromium/ui/views/widget/root_view.cc16
-rw-r--r--chromium/ui/views/widget/root_view.h4
-rw-r--r--chromium/ui/views/widget/root_view_unittest.cc14
-rw-r--r--chromium/ui/views/widget/widget.cc34
-rw-r--r--chromium/ui/views/widget/widget.h48
-rw-r--r--chromium/ui/views/widget/widget_aura_utils.cc2
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc6
-rw-r--r--chromium/ui/views/widget/widget_delegate.h13
-rw-r--r--chromium/ui/views/widget/widget_hwnd_utils.cc13
-rw-r--r--chromium/ui/views/widget/widget_hwnd_utils.h4
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc237
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc383
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc39
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.h6
-rw-r--r--chromium/ui/views/win/hwnd_message_handler_delegate.h8
-rw-r--r--chromium/ui/views/window/caption_button_layout_constants.cc26
-rw-r--r--chromium/ui/views/window/caption_button_layout_constants.h39
-rw-r--r--chromium/ui/views/window/caption_button_types.h27
-rw-r--r--chromium/ui/views/window/custom_frame_view.cc6
-rw-r--r--chromium/ui/views/window/custom_frame_view.h2
-rw-r--r--chromium/ui/views/window/dialog_client_view.cc10
-rw-r--r--chromium/ui/views/window/dialog_client_view.h2
-rw-r--r--chromium/ui/views/window/dialog_delegate.cc60
-rw-r--r--chromium/ui/views/window/dialog_delegate.h29
-rw-r--r--chromium/ui/views/window/dialog_delegate_unittest.cc8
-rw-r--r--chromium/ui/views/window/dialog_observer.h4
-rw-r--r--chromium/ui/views/window/frame_caption_button.cc297
-rw-r--r--chromium/ui/views/window/frame_caption_button.h133
-rw-r--r--chromium/ui/views/window/frame_caption_button_unittest.cc29
-rw-r--r--chromium/ui/views/window/native_frame_view.cc2
-rw-r--r--chromium/ui/views/window/native_frame_view.h2
-rw-r--r--chromium/ui/views/window/non_client_view.cc11
-rw-r--r--chromium/ui/views/window/non_client_view.h13
-rw-r--r--chromium/ui/views/window/vector_icons/BUILD.gn27
-rw-r--r--chromium/ui/views/window/vector_icons/vector_icons.cc.template20
-rw-r--r--chromium/ui/views/window/vector_icons/vector_icons.h.template26
-rw-r--r--chromium/ui/views/window/vector_icons/window_control_close.icon35
-rw-r--r--chromium/ui/views/window/vector_icons/window_control_maximize.icon31
-rw-r--r--chromium/ui/views/window/vector_icons/window_control_minimize.icon17
-rw-r--r--chromium/ui/views/window/vector_icons/window_control_restore.icon47
-rw-r--r--chromium/ui/views/window/window_shape.cc7
-rw-r--r--chromium/ui/views/window/window_shape.h5
-rw-r--r--chromium/ui/views_bridge_mac/BUILD.gn18
-rw-r--r--chromium/ui/views_bridge_mac/alert.h65
-rw-r--r--chromium/ui/views_bridge_mac/alert.mm318
-rw-r--r--chromium/ui/views_bridge_mac/bridge_factory_impl.h5
-rw-r--r--chromium/ui/views_bridge_mac/bridge_factory_impl.mm34
-rw-r--r--chromium/ui/views_bridge_mac/bridged_content_view.h20
-rw-r--r--chromium/ui/views_bridge_mac/bridged_content_view.mm366
-rw-r--r--chromium/ui/views_bridge_mac/bridged_native_widget_host_helper.h14
-rw-r--r--chromium/ui/views_bridge_mac/bridged_native_widget_impl.h36
-rw-r--r--chromium/ui/views_bridge_mac/bridged_native_widget_impl.mm55
-rw-r--r--chromium/ui/views_bridge_mac/mojo/alert.mojom51
-rw-r--r--chromium/ui/views_bridge_mac/mojo/bridge_factory.mojom8
-rw-r--r--chromium/ui/views_bridge_mac/mojo/bridged_native_widget.mojom5
-rw-r--r--chromium/ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom73
-rw-r--r--chromium/ui/views_bridge_mac/mojo/text_input_host.mojom81
-rw-r--r--chromium/ui/views_bridge_mac/native_widget_mac_nswindow.mm7
-rw-r--r--chromium/ui/views_bridge_mac/views_nswindow_delegate.mm11
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts.cc5
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts.h3
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts_mac.mm12
-rw-r--r--chromium/ui/views_content_client/views_content_main_delegate.cc6
-rw-r--r--chromium/ui/views_content_client/views_content_main_delegate.h1
-rw-r--r--chromium/ui/webui/resources/.eslintrc.js (renamed from chromium/ui/webui/resources/cr_components/.eslintrc.js)1
-rw-r--r--chromium/ui/webui/resources/PRESUBMIT.py2
-rw-r--r--chromium/ui/webui/resources/cr_components/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.js2
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.js4
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_list.js8
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js8
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager_types.js8
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.js2
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html8
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js2
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js14
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js96
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn12
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/OWNERS4
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.html2
-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.js28
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_failed_page.html18
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_failed_page.js43
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js13
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js15
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_choose_mobile.js20
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js155
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.js9
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html14
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js63
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html35
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js54
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.js12
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js42
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js60
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js89
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js51
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js16
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html72
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js137
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.js25
-rw-r--r--chromium/ui/webui/resources/cr_components/cr_components_resources.grdp16
-rw-r--r--chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn19
-rw-r--r--chromium/ui/webui/resources/cr_components/managed_footnote/managed_footnote.html48
-rw-r--r--chromium/ui/webui/resources/cr_components/managed_footnote/managed_footnote.js69
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js15
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js24
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html2
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js27
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_png_behavior.js24
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/fingerprint/cr_fingerprint_progress_arc.js8
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js49
-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.js24
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js3
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js12
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js115
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html15
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js61
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html50
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js9
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_container_shadow_behavior.js3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html16
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js39
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html9
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js11
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html30
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js6
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_icons_css.html76
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js38
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html19
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js15
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html12
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js9
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js12
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html22
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js47
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js17
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn10
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html95
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.js33
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js9
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html10
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js43
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.html31
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js208
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html24
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html37
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js15
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html12
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html2
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js15
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html9
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js3
-rw-r--r--chromium/ui/webui/resources/cr_elements/icons.html6
-rw-r--r--chromium/ui/webui/resources/cr_elements/paper_button_style_css.html128
-rw-r--r--chromium/ui/webui/resources/cr_elements/paper_tabs_style_css.html11
-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.js105
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js9
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js6
-rw-r--r--chromium/ui/webui/resources/cr_elements/shared_vars_css.html149
-rw-r--r--chromium/ui/webui/resources/cr_elements_images.grdp20
-rw-r--r--chromium/ui/webui/resources/cr_elements_resources.grdp26
-rw-r--r--chromium/ui/webui/resources/cr_polymer_resources.grdp6
-rw-r--r--chromium/ui/webui/resources/css/i18n_process.css10
-rw-r--r--chromium/ui/webui/resources/css/md_colors.css11
-rw-r--r--chromium/ui/webui/resources/css/text_defaults.css1
-rw-r--r--chromium/ui/webui/resources/css/text_defaults_md.css1
-rw-r--r--chromium/ui/webui/resources/html/action_link_css.html4
-rw-r--r--chromium/ui/webui/resources/html/cr/ui/focus_row_behavior.html2
-rw-r--r--chromium/ui/webui/resources/html/cr/ui/store.html1
-rw-r--r--chromium/ui/webui/resources/html/cr/ui/store_client.html1
-rw-r--r--chromium/ui/webui/resources/html/dark_mode.html2
-rw-r--r--chromium/ui/webui/resources/html/find_shortcut_behavior.html4
-rw-r--r--chromium/ui/webui/resources/html/i18n_behavior.html2
-rw-r--r--chromium/ui/webui/resources/html/icon.html4
-rw-r--r--chromium/ui/webui/resources/html/load_time_data.html4
-rw-r--r--chromium/ui/webui/resources/html/md_select_css.html37
-rw-r--r--chromium/ui/webui/resources/html/promise_resolver.html2
-rw-r--r--chromium/ui/webui/resources/html/util.html2
-rw-r--r--chromium/ui/webui/resources/html/web_ui_listener_behavior.html2
-rw-r--r--chromium/ui/webui/resources/html/webui_listener_tracker.html1
-rw-r--r--chromium/ui/webui/resources/images/add.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/arrow_down.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/arrow_right.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_arrow_back.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_arrow_dropdown.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_cancel.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_clear.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_delete_gray.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_expand_less.svg4
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_expand_more.svg4
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_more_vert.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_picture_delete.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_refresh.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_search.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_settings.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_toolbar_cancel.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_toolbar_menu.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_visibility.svg1
-rw-r--r--chromium/ui/webui/resources/images/dark/icon_visibility_off.svg1
-rw-r--r--chromium/ui/webui/resources/images/error_badge.svg9
-rw-r--r--chromium/ui/webui/resources/images/icon_picture_delete.svg (renamed from chromium/ui/webui/resources/images/icon_delete_white.svg)0
-rw-r--r--chromium/ui/webui/resources/images/icon_toolbar_cancel.svg (renamed from chromium/ui/webui/resources/images/icon_cancel_toolbar.svg)0
-rw-r--r--chromium/ui/webui/resources/images/icon_toolbar_menu.svg (renamed from chromium/ui/webui/resources/images/icon_menu_white.svg)0
-rw-r--r--chromium/ui/webui/resources/js/BUILD.gn21
-rw-r--r--chromium/ui/webui/resources/js/action_link.js21
-rw-r--r--chromium/ui/webui/resources/js/assert.js12
-rw-r--r--chromium/ui/webui/resources/js/cr.js120
-rw-r--r--chromium/ui/webui/resources/js/cr/event_target.js39
-rw-r--r--chromium/ui/webui/resources/js/cr/link_controller.js20
-rw-r--r--chromium/ui/webui/resources/js/cr/ui.js63
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/BUILD.gn39
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/array_data_model.js123
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js45
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/bubble.js118
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/bubble_button.js8
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/card_slider.js93
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/command.js45
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/context_menu_button.js15
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js67
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js25
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/dialogs.js48
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js11
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/expandable_bubble.js47
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_grid.js55
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_manager.js31
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js11
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_row.js91
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js327
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js19
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/grid.js96
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list.js428
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list_item.js5
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js58
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list_selection_model.js82
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list_single_selection_model.js41
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/menu.js86
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/menu_button.js60
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/menu_item.js58
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/node_utils.js25
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/overlay.js51
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/page_manager/BUILD.gn31
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/page_manager/page.js35
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/page_manager/page_manager.js186
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/position_util.js48
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/repeating_button.js6
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/splitter.js49
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/store.js167
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/store_client.js137
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/table.js88
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/table/table_column.js6
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/table/table_column_model.js55
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/table/table_header.js90
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/table/table_list.js58
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/table/table_splitter.js6
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/tabs.js53
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/touch_handler.js80
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/tree.js180
-rw-r--r--chromium/ui/webui/resources/js/dark_mode.js10
-rw-r--r--chromium/ui/webui/resources/js/event_tracker.js5
-rw-r--r--chromium/ui/webui/resources/js/find_shortcut_behavior.js114
-rw-r--r--chromium/ui/webui/resources/js/i18n_behavior.js12
-rw-r--r--chromium/ui/webui/resources/js/i18n_template_no_process.js87
-rw-r--r--chromium/ui/webui/resources/js/icon.js37
-rw-r--r--chromium/ui/webui/resources/js/list_property_update_behavior.js3
-rw-r--r--chromium/ui/webui/resources/js/load_time_data.js28
-rw-r--r--chromium/ui/webui/resources/js/parse_html_subset.js43
-rw-r--r--chromium/ui/webui/resources/js/promise_resolver.js21
-rw-r--r--chromium/ui/webui/resources/js/search_highlight_utils.js6
-rw-r--r--chromium/ui/webui/resources/js/template_data_externs.js2
-rw-r--r--chromium/ui/webui/resources/js/util.js91
-rw-r--r--chromium/ui/webui/resources/js/web_ui_listener_behavior.js1
-rw-r--r--chromium/ui/webui/resources/js/webui_listener_tracker.js42
-rw-r--r--chromium/ui/webui/resources/js/webui_resource_test.js75
-rw-r--r--chromium/ui/webui/resources/polymer_resources.grdp320
-rw-r--r--chromium/ui/webui/resources/webui_resources.grd34
-rw-r--r--chromium/ui/wm/core/base_focus_rules.cc81
-rw-r--r--chromium/ui/wm/core/base_focus_rules.h19
-rw-r--r--chromium/ui/wm/core/compound_event_filter.cc1
-rw-r--r--chromium/ui/wm/core/default_activation_client.cc8
-rw-r--r--chromium/ui/wm/core/default_activation_client.h7
-rw-r--r--chromium/ui/wm/core/focus_controller.cc48
-rw-r--r--chromium/ui/wm/core/focus_controller.h21
-rw-r--r--chromium/ui/wm/core/focus_controller_unittest.cc128
-rw-r--r--chromium/ui/wm/core/focus_rules.h10
-rw-r--r--chromium/ui/wm/core/ime_util_chromeos.cc28
-rw-r--r--chromium/ui/wm/core/shadow_controller.cc8
-rw-r--r--chromium/ui/wm/core/shadow_controller_unittest.cc43
-rw-r--r--chromium/ui/wm/core/shadow_types.cc1
-rw-r--r--chromium/ui/wm/core/window_modality_controller.cc29
-rw-r--r--chromium/ui/wm/core/window_modality_controller.h2
-rw-r--r--chromium/ui/wm/core/window_util.cc21
-rw-r--r--chromium/ui/wm/core/window_util.h9
-rw-r--r--chromium/ui/wm/public/activation_client.h7
-rw-r--r--chromium/ui/wm/public/activation_delegate.cc2
-rw-r--r--chromium/ui/wm/public/activation_delegate.h2
1356 files changed, 33494 insertions, 14116 deletions
diff --git a/chromium/ui/OWNERS b/chromium/ui/OWNERS
index 8173fdea55a..4f49426556c 100644
--- a/chromium/ui/OWNERS
+++ b/chromium/ui/OWNERS
@@ -8,3 +8,6 @@ ccameron@chromium.org
# If you're doing structural changes get a review from one of the OWNERS.
per-file BUILD.gn=*
+
+# Translation artifacts:
+per-file *.xtb=file://tools/translation/TRANSLATION_OWNERS
diff --git a/chromium/ui/accelerated_widget_mac/window_resize_helper_mac.cc b/chromium/ui/accelerated_widget_mac/window_resize_helper_mac.cc
index 6079d8fcb31..68a47c0bc1a 100644
--- a/chromium/ui/accelerated_widget_mac/window_resize_helper_mac.cc
+++ b/chromium/ui/accelerated_widget_mac/window_resize_helper_mac.cc
@@ -319,7 +319,8 @@ WindowResizeHelperMac::~WindowResizeHelperMac() {}
void WindowResizeHelperMac::EventTimedWait(base::WaitableEvent* event,
base::TimeDelta delay) {
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ // http://crbug.com/902829
+ base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
event->TimedWait(delay);
}
diff --git a/chromium/ui/accessibility/BUILD.gn b/chromium/ui/accessibility/BUILD.gn
index fc631e4e1fc..8870c51a35a 100644
--- a/chromium/ui/accessibility/BUILD.gn
+++ b/chromium/ui/accessibility/BUILD.gn
@@ -2,9 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/config/linux/pkg_config.gni")
import("//build/config/features.gni")
import("//build/config/jumbo.gni")
+import("//build/config/linux/pkg_config.gni")
import("//build/config/ui.gni")
import("//mojo/public/tools/bindings/mojom.gni")
import("//services/service_manager/public/service_manifest.gni")
@@ -17,16 +17,13 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-mojom("ax_enums_mojo") {
+mojom_component("ax_enums_mojo") {
sources = [
"ax_enums.mojom",
]
- public_deps = [
- "//mojo/public/mojom/base",
- "//ui/gfx/geometry/mojo",
- "//ui/gfx/mojo",
- ]
+ macro_prefix = "UI_ACCESSIBILITY_AX_MOJOM"
+ output_prefix = "ui_accessibility_ax_mojom"
}
jumbo_component("accessibility") {
@@ -35,15 +32,16 @@ jumbo_component("accessibility") {
"accessibility_switches.h",
"ax_action_data.cc",
"ax_action_data.h",
+ "ax_action_handler.cc",
+ "ax_action_handler.h",
"ax_enum_util.cc",
"ax_enum_util.h",
"ax_event.cc",
"ax_event.h",
+ "ax_event_bundle_sink.h",
"ax_event_generator.cc",
"ax_event_generator.h",
"ax_export.h",
- "ax_host_delegate.cc",
- "ax_host_delegate.h",
"ax_language_info.h",
"ax_mode.h",
"ax_mode_observer.h",
@@ -75,6 +73,8 @@ jumbo_component("accessibility") {
"ax_tree_id.h",
"ax_tree_id_registry.cc",
"ax_tree_id_registry.h",
+ "ax_tree_observer.cc",
+ "ax_tree_observer.h",
"ax_tree_serializer.cc",
"ax_tree_serializer.h",
"ax_tree_source.h",
@@ -92,6 +92,8 @@ jumbo_component("accessibility") {
"platform/ax_platform_node_test_helper.h",
"platform/ax_unique_id.cc",
"platform/ax_unique_id.h",
+ "platform/compute_attributes.cc",
+ "platform/compute_attributes.h",
]
if (has_native_accessibility) {
@@ -188,6 +190,7 @@ service_manifest("manifest") {
static_library("test_support") {
testonly = true
sources = [
+ "ax_tree_source_checker.h",
"tree_generator.cc",
"tree_generator.h",
]
diff --git a/chromium/ui/accessibility/accessibility_switches.cc b/chromium/ui/accessibility/accessibility_switches.cc
index 5428cb21f43..3db61d6be48 100644
--- a/chromium/ui/accessibility/accessibility_switches.cc
+++ b/chromium/ui/accessibility/accessibility_switches.cc
@@ -17,13 +17,31 @@ const char kEnableExperimentalAccessibilityFeatures[] =
const char kEnableExperimentalAccessibilityAutoclick[] =
"enable-experimental-accessibility-autoclick";
+// Enables additional image label features that haven't launched yet.
+const char kEnableExperimentalAccessibilityLabels[] =
+ "enable-experimental-accessibility-labels";
+
+// Enables language detection on in-page text content which is then exposed to
+// accessibility technology such as screen readers.
+const char kEnableExperimentalAccessibilityLanguageDetection[] =
+ "enable-experimental-accessibility-language-detection";
+
// Shows setting to enable Switch Access before it has launched.
const char kEnableExperimentalAccessibilitySwitchAccess[] =
"enable-experimental-accessibility-switch-access";
+// Enables language switching feature that hasn't launched yet.
+const char kEnableExperimentalAccessibilityChromeVoxLanguageSwitching[] =
+ "enable-experimental-accessibility-chromevox-language-switching";
+
bool AreExperimentalAccessibilityFeaturesEnabled() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
::switches::kEnableExperimentalAccessibilityFeatures);
}
+bool AreExperimentalAccessibilityLanguageDetectionEnabled() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ ::switches::kEnableExperimentalAccessibilityLanguageDetection);
+}
+
} // namespace switches
diff --git a/chromium/ui/accessibility/accessibility_switches.h b/chromium/ui/accessibility/accessibility_switches.h
index 70588cd9501..b22760236dc 100644
--- a/chromium/ui/accessibility/accessibility_switches.h
+++ b/chromium/ui/accessibility/accessibility_switches.h
@@ -12,11 +12,17 @@ namespace switches {
AX_EXPORT extern const char kEnableExperimentalAccessibilityFeatures[];
AX_EXPORT extern const char kEnableExperimentalAccessibilityAutoclick[];
+AX_EXPORT extern const char kEnableExperimentalAccessibilityLabels[];
+AX_EXPORT extern const char kEnableExperimentalAccessibilityLanguageDetection[];
AX_EXPORT extern const char kEnableExperimentalAccessibilitySwitchAccess[];
+AX_EXPORT extern const char
+ kEnableExperimentalAccessibilityChromeVoxLanguageSwitching[];
// Returns true if experimental accessibility features are enabled.
AX_EXPORT bool AreExperimentalAccessibilityFeaturesEnabled();
+// Returns true if experimental accessibility language detection is enabled.
+AX_EXPORT bool AreExperimentalAccessibilityLanguageDetectionEnabled();
} // namespace switches
#endif // UI_ACCESSIBILITY_ACCESSIBILITY_SWITCHES_H_
diff --git a/chromium/ui/accessibility/ax_host_delegate.cc b/chromium/ui/accessibility/ax_action_handler.cc
index 9e7104d488e..a570205cab8 100644
--- a/chromium/ui/accessibility/ax_host_delegate.cc
+++ b/chromium/ui/accessibility/ax_action_handler.cc
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/accessibility/ax_host_delegate.h"
+#include "ui/accessibility/ax_action_handler.h"
#include "ui/accessibility/ax_tree_id_registry.h"
namespace ui {
-AXHostDelegate::AXHostDelegate()
- : tree_id_(AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID(this)) {}
-
-AXHostDelegate::AXHostDelegate(AXTreeID tree_id) : tree_id_(tree_id) {
- AXTreeIDRegistry::GetInstance()->SetDelegateForID(this, tree_id);
+bool AXActionHandler::RequiresPerformActionPointInPixels() const {
+ return false;
}
-AXHostDelegate::~AXHostDelegate() {
+AXActionHandler::AXActionHandler()
+ : tree_id_(AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID(this)) {}
+
+AXActionHandler::~AXActionHandler() {
AXTreeIDRegistry::GetInstance()->RemoveAXTreeID(tree_id_);
}
diff --git a/chromium/ui/accessibility/ax_host_delegate.h b/chromium/ui/accessibility/ax_action_handler.h
index 4d4960914cf..35b31e59ecf 100644
--- a/chromium/ui/accessibility/ax_host_delegate.h
+++ b/chromium/ui/accessibility/ax_action_handler.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_ACCESSIBILITY_AX_HOST_DELEGATE_H_
-#define UI_ACCESSIBILITY_AX_HOST_DELEGATE_H_
+#ifndef UI_ACCESSIBILITY_AX_ACTION_HANDLER_H_
+#define UI_ACCESSIBILITY_AX_ACTION_HANDLER_H_
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree_id.h"
@@ -14,36 +14,36 @@ struct AXActionData;
// Classes that host an accessibility tree in the browser process that also wish
// to become visible to accessibility clients (e.g. for relaying targets to
-// source accessibility trees), can subclass this delegate.
+// source accessibility trees), can subclass this class.
//
// Subclasses can use |tree_id| when annotating their |AXNodeData| for clients
// to respond with the appropriate target node id.
-class AX_EXPORT AXHostDelegate {
+class AX_EXPORT AXActionHandler {
public:
- virtual ~AXHostDelegate();
+ virtual ~AXActionHandler();
// Handle an action from an accessibility client.
- virtual void PerformAction(const ui::AXActionData& data) = 0;
+ virtual void PerformAction(const AXActionData& data) = 0;
+
+ // Returns whether this handler expects points in pixels (true) or dips
+ // (false) for data passed to |PerformAction|.
+ virtual bool RequiresPerformActionPointInPixels() const;
// A tree id appropriate for annotating events sent to an accessibility
// client.
- AXTreeID tree_id() const { return tree_id_; }
+ const AXTreeID& ax_tree_id() const { return tree_id_; };
protected:
- // A delegate with an automatically assigned tree id.
- AXHostDelegate();
-
- // A delegate with an explicit tree id. The caller is responsible for ensuring
- // the uniqueness of the id.
- explicit AXHostDelegate(AXTreeID tree_id);
+ AXActionHandler();
private:
// Register or unregister this class with |AXTreeIDRegistry|.
void UpdateActiveState(bool active);
+ // Automatically assigned.
AXTreeID tree_id_;
};
} // namespace ui
-#endif // UI_ACCESSIBILITY_AX_HOST_DELEGATE_H_
+#endif // UI_ACCESSIBILITY_AX_ACTION_HANDLER_H_
diff --git a/chromium/ui/accessibility/ax_enum_util.cc b/chromium/ui/accessibility/ax_enum_util.cc
index cb523c47c62..901c127e23e 100644
--- a/chromium/ui/accessibility/ax_enum_util.cc
+++ b/chromium/ui/accessibility/ax_enum_util.cc
@@ -70,6 +70,8 @@ const char* ToString(ax::mojom::Event event) {
return "menuListValueChanged";
case ax::mojom::Event::kMenuPopupEnd:
return "menuPopupEnd";
+ case ax::mojom::Event::kMenuPopupHide:
+ return "menuPopupHide";
case ax::mojom::Event::kMenuPopupStart:
return "menuPopupStart";
case ax::mojom::Event::kMenuStart:
@@ -184,6 +186,8 @@ ax::mojom::Event ParseEvent(const char* event) {
return ax::mojom::Event::kMenuListValueChanged;
if (0 == strcmp(event, "menuPopupEnd"))
return ax::mojom::Event::kMenuPopupEnd;
+ if (0 == strcmp(event, "menuPopupHide"))
+ return ax::mojom::Event::kMenuPopupHide;
if (0 == strcmp(event, "menuPopupStart"))
return ax::mojom::Event::kMenuPopupStart;
if (0 == strcmp(event, "menuStart"))
@@ -449,16 +453,18 @@ const char* ToString(ax::mojom::Role role) {
return "lineBreak";
case ax::mojom::Role::kLink:
return "link";
+ case ax::mojom::Role::kList:
+ return "list";
case ax::mojom::Role::kListBoxOption:
return "listBoxOption";
case ax::mojom::Role::kListBox:
return "listBox";
+ case ax::mojom::Role::kListGrid:
+ return "listGrid";
case ax::mojom::Role::kListItem:
return "listItem";
case ax::mojom::Role::kListMarker:
return "listMarker";
- case ax::mojom::Role::kList:
- return "list";
case ax::mojom::Role::kLog:
return "log";
case ax::mojom::Role::kMain:
@@ -547,10 +553,10 @@ const char* ToString(ax::mojom::Role role) {
return "tabPanel";
case ax::mojom::Role::kTab:
return "tab";
- case ax::mojom::Role::kTableHeaderContainer:
- return "tableHeaderContainer";
case ax::mojom::Role::kTable:
return "table";
+ case ax::mojom::Role::kTableHeaderContainer:
+ return "tableHeaderContainer";
case ax::mojom::Role::kTerm:
return "term";
case ax::mojom::Role::kTextField:
diff --git a/chromium/ui/accessibility/ax_enums.mojom b/chromium/ui/accessibility/ax_enums.mojom
index 905352e5a03..0a1a75fb6eb 100644
--- a/chromium/ui/accessibility/ax_enums.mojom
+++ b/chromium/ui/accessibility/ax_enums.mojom
@@ -56,8 +56,9 @@ enum Event {
kMenuEnd, // Native / Win
kMenuListItemSelected, // Web
kMenuListValueChanged, // Web
- kMenuPopupEnd, // Native / Win
- kMenuPopupStart, // Native / Win
+ kMenuPopupEnd, // Native
+ kMenuPopupHide, // Native / AuraLinux
+ kMenuPopupStart, // Native
kMenuStart, // Native / Win
kMouseCanceled,
kMouseDragged,
@@ -85,12 +86,18 @@ enum Event {
kValueChanged,
};
-// Explanation:
+// Accessibility object roles.
// The majority of these roles come from the ARIA specification. Reference
// the latest draft for proper usage.
//
// Roles not included by the ARIA specification should be avoided, especially
// internal roles used by the accessibility infrastructure.
+//
+// Explanation of in-lined comments next to some enum values.
+ //
+ // Web: this attribute is only used in web content.
+ //
+ // Native: this attribute is only used in native UI.
enum Role {
kNone,
kAbbr,
@@ -212,6 +219,10 @@ enum Role {
kList,
kListBox,
kListBoxOption,
+ // kListGrid behaves similar to an ARIA grid but is primarily used by
+ // TableView and its subclasses, so that they could be exposed correctly on
+ // certain platforms.
+ kListGrid, // Native
kListItem,
kListMarker,
kLog,
@@ -872,3 +883,10 @@ enum TreeOrder {
// First node is after the second one.
kAfter,
};
+
+// For internal use by ui::AXTreeID / ax::mojom::AXTreeID.
+enum AXTreeIDType {
+ kUnknown, // The Tree ID is unknown.
+ kToken, // Every other tree ID must have a valid unguessable token.
+};
+
diff --git a/chromium/ui/accessibility/ax_event_bundle_sink.h b/chromium/ui/accessibility/ax_event_bundle_sink.h
new file mode 100644
index 00000000000..897a4a94b4a
--- /dev/null
+++ b/chromium/ui/accessibility/ax_event_bundle_sink.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_ACCESSIBILITY_AX_EVENT_BUNDLE_SINK_H_
+#define UI_ACCESSIBILITY_AX_EVENT_BUNDLE_SINK_H_
+
+#include <vector>
+
+#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_tree_update.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+struct AXEvent;
+class AXTreeID;
+
+// Interface for a consumer of groups of AXEvents.
+class AX_EXPORT AXEventBundleSink {
+ public:
+ // |tree_id|: ID of the accessibility tree that the events apply to.
+ // |updates|: Zero or more updates to the accessibility tree to apply first.
+ // |mouse location|: Current mouse location in screen coordinates.
+ // |events|: Zero or more events to fire after the updates have been applied.
+ // Callers may wish to std::move() into the vector params to avoid copies.
+ virtual void DispatchAccessibilityEvents(const AXTreeID& tree_id,
+ std::vector<AXTreeUpdate> updates,
+ const gfx::Point& mouse_location,
+ std::vector<AXEvent> events) = 0;
+
+ protected:
+ virtual ~AXEventBundleSink() {}
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_EVENT_BUNDLE_SINK_H_
diff --git a/chromium/ui/accessibility/ax_event_generator.cc b/chromium/ui/accessibility/ax_event_generator.cc
index d96824cbfe7..ffc7053460d 100644
--- a/chromium/ui/accessibility/ax_event_generator.cc
+++ b/chromium/ui/accessibility/ax_event_generator.cc
@@ -68,20 +68,20 @@ AXEventGenerator::AXEventGenerator() = default;
AXEventGenerator::AXEventGenerator(AXTree* tree) : tree_(tree) {
if (tree_)
- tree_->SetDelegate(this);
+ tree_->AddObserver(this);
}
AXEventGenerator::~AXEventGenerator() {
if (tree_)
- tree_->SetDelegate(nullptr);
+ tree_->RemoveObserver(this);
}
void AXEventGenerator::SetTree(AXTree* new_tree) {
if (tree_)
- tree_->SetDelegate(nullptr);
+ tree_->RemoveObserver(this);
tree_ = new_tree;
if (tree_)
- tree_->SetDelegate(this);
+ tree_->AddObserver(this);
}
void AXEventGenerator::ReleaseTree() {
@@ -203,7 +203,9 @@ void AXEventGenerator::OnStringAttributeChanged(AXTree* tree,
case ax::mojom::StringAttribute::kLiveStatus:
// TODO(accessibility): tree in the midst of updates. Disallow access to
// |node|.
- if (node->data().role != ax::mojom::Role::kAlert)
+ if (node->data().GetStringAttribute(
+ ax::mojom::StringAttribute::kLiveStatus) != "off" &&
+ node->data().role != ax::mojom::Role::kAlert)
AddEvent(node, Event::LIVE_REGION_CREATED);
break;
default:
@@ -290,15 +292,6 @@ void AXEventGenerator::OnIntListAttributeChanged(
AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
}
-void AXEventGenerator::OnStringListAttributeChanged(
- AXTree* tree,
- AXNode* node,
- ax::mojom::StringListAttribute attr,
- const std::vector<std::string>& old_value,
- const std::vector<std::string>& new_value) {
- DCHECK_EQ(tree_, tree);
-}
-
void AXEventGenerator::OnTreeDataChanged(AXTree* tree,
const ui::AXTreeData& old_tree_data,
const ui::AXTreeData& new_tree_data) {
@@ -340,18 +333,6 @@ void AXEventGenerator::OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) {
DCHECK_EQ(tree_, tree);
}
-void AXEventGenerator::OnNodeCreated(AXTree* tree, AXNode* node) {
- DCHECK_EQ(tree_, tree);
-}
-
-void AXEventGenerator::OnNodeReparented(AXTree* tree, AXNode* node) {
- DCHECK_EQ(tree_, tree);
-}
-
-void AXEventGenerator::OnNodeChanged(AXTree* tree, AXNode* node) {
- DCHECK_EQ(tree_, tree);
-}
-
void AXEventGenerator::OnAtomicUpdateFinished(
AXTree* tree,
bool root_changed,
@@ -371,7 +352,8 @@ void AXEventGenerator::OnAtomicUpdateFinished(
ax::mojom::StringAttribute::kLiveStatus)) {
if (change.node->data().role == ax::mojom::Role::kAlert)
AddEvent(change.node, Event::ALERT);
- else
+ else if (change.node->data().GetStringAttribute(
+ ax::mojom::StringAttribute::kLiveStatus) != "off")
AddEvent(change.node, Event::LIVE_REGION_CREATED);
} else if (change.node->data().HasStringAttribute(
ax::mojom::StringAttribute::kContainerLiveStatus) &&
@@ -395,7 +377,9 @@ void AXEventGenerator::FireLiveRegionEvents(AXNode* node) {
live_root = live_root->parent();
if (live_root &&
- !live_root->data().GetBoolAttribute(ax::mojom::BoolAttribute::kBusy)) {
+ !live_root->data().GetBoolAttribute(ax::mojom::BoolAttribute::kBusy) &&
+ live_root->data().GetStringAttribute(
+ ax::mojom::StringAttribute::kLiveStatus) != "off") {
// Fire LIVE_REGION_NODE_CHANGED on each node that changed.
if (!node->data()
.GetStringAttribute(ax::mojom::StringAttribute::kName)
@@ -453,8 +437,16 @@ void AXEventGenerator::FireRelationSourceEvents(AXTree* tree,
std::for_each(tree->int_reverse_relations().begin(),
tree->int_reverse_relations().end(), callback);
- std::for_each(tree->intlist_reverse_relations().begin(),
- tree->intlist_reverse_relations().end(), callback);
+ std::for_each(
+ tree->intlist_reverse_relations().begin(),
+ tree->intlist_reverse_relations().end(), [&](auto& entry) {
+ // Explicitly exclude relationships for which an additional event on the
+ // source node would cause extra noise. For example, kRadioGroupIds
+ // forms relations among all radio buttons and serves little value for
+ // AT to get events on the previous radio button in the group.
+ if (entry.first != ax::mojom::IntListAttribute::kRadioGroupIds)
+ callback(entry);
+ });
}
// Attempts to suppress load-related events that we presume no AT will be
diff --git a/chromium/ui/accessibility/ax_event_generator.h b/chromium/ui/accessibility/ax_event_generator.h
index 4e84982bcf9..268dd3fa43c 100644
--- a/chromium/ui/accessibility/ax_event_generator.h
+++ b/chromium/ui/accessibility/ax_event_generator.h
@@ -11,14 +11,15 @@
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_observer.h"
namespace ui {
-// Subclass of AXTreeDelegate that automatically generates AXEvents to fire
+// Subclass of AXTreeObserver that automatically generates AXEvents to fire
// based on changes to an accessibility tree. Every platform
// tends to want different events, so this class lets each platform
// handle the events it wants and ignore the others.
-class AX_EXPORT AXEventGenerator : public AXTreeDelegate {
+class AX_EXPORT AXEventGenerator : public AXTreeObserver {
public:
enum class Event : int32_t {
ACTIVE_DESCENDANT_CHANGED,
@@ -87,14 +88,14 @@ class AX_EXPORT AXEventGenerator : public AXTreeDelegate {
// before using this class.
AXEventGenerator();
- // Automatically registers itself as the delegate of |tree| and
+ // Automatically registers itself as the observer of |tree| and
// clears it on desctruction. |tree| must be valid for the lifetime
// of this object.
explicit AXEventGenerator(AXTree* tree);
~AXEventGenerator() override;
- // Clears this class as the delegate of the previous tree that was
+ // Clears this class as the observer of the previous tree that was
// being monitored, if any, and starts monitoring |new_tree|, if not
// nullptr. Note that |new_tree| must be valid for the lifetime of
// this object or until you call SetTree again.
@@ -112,7 +113,7 @@ class AX_EXPORT AXEventGenerator : public AXTreeDelegate {
void ClearEvents();
// This is called automatically based on changes to the tree observed
- // by AXTreeDelegate, but you can also call it directly to add events
+ // by AXTreeObserver, but you can also call it directly to add events
// and retrieve them later.
//
// Note that events are organized by node and then by event id to
@@ -126,7 +127,7 @@ class AX_EXPORT AXEventGenerator : public AXTreeDelegate {
}
protected:
- // AXTreeDelegate overrides.
+ // AXTreeObserver overrides.
void OnNodeDataWillChange(AXTree* tree,
const AXNodeData& old_node_data,
const AXNodeData& new_node_data) override;
@@ -163,12 +164,6 @@ class AX_EXPORT AXEventGenerator : public AXTreeDelegate {
ax::mojom::IntListAttribute attr,
const std::vector<int32_t>& old_value,
const std::vector<int32_t>& new_value) override;
- void OnStringListAttributeChanged(
- AXTree* tree,
- AXNode* node,
- ax::mojom::StringListAttribute attr,
- const std::vector<std::string>& old_value,
- const std::vector<std::string>& new_value) override;
void OnTreeDataChanged(AXTree* tree,
const ui::AXTreeData& old_data,
const ui::AXTreeData& new_data) override;
@@ -176,9 +171,6 @@ class AX_EXPORT AXEventGenerator : public AXTreeDelegate {
void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) override;
void OnNodeWillBeReparented(AXTree* tree, AXNode* node) override;
void OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) override;
- void OnNodeCreated(AXTree* tree, AXNode* node) override;
- void OnNodeReparented(AXTree* tree, AXNode* node) override;
- void OnNodeChanged(AXTree* tree, AXNode* node) override;
void OnAtomicUpdateFinished(AXTree* tree,
bool root_changed,
const std::vector<Change>& changes) override;
diff --git a/chromium/ui/accessibility/ax_event_generator_unittest.cc b/chromium/ui/accessibility/ax_event_generator_unittest.cc
index 923b163f935..6b17f7b9aee 100644
--- a/chromium/ui/accessibility/ax_event_generator_unittest.cc
+++ b/chromium/ui/accessibility/ax_event_generator_unittest.cc
@@ -831,4 +831,39 @@ TEST(AXEventGeneratorTest, NodeBecomesUnignored) {
DumpEvents(&event_generator));
}
+TEST(AXEventGeneratorTest, ActiveDescendantChangeOnDescendant) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(5);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+ initial_state.nodes[0].child_ids.push_back(2);
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kGenericContainer;
+ initial_state.nodes[1].child_ids.push_back(3);
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kGroup;
+ initial_state.nodes[2].AddIntAttribute(
+ ax::mojom::IntAttribute::kActivedescendantId, 4);
+ initial_state.nodes[2].child_ids.push_back(4);
+ initial_state.nodes[2].child_ids.push_back(5);
+ initial_state.nodes[3].id = 4;
+ initial_state.nodes[3].role = ax::mojom::Role::kGroup;
+ initial_state.nodes[4].id = 5;
+ initial_state.nodes[4].role = ax::mojom::Role::kGroup;
+
+ AXTree tree(initial_state);
+
+ AXEventGenerator event_generator(&tree);
+ initial_state.nodes[2].RemoveIntAttribute(
+ ax::mojom::IntAttribute::kActivedescendantId);
+ initial_state.nodes[2].AddIntAttribute(
+ ax::mojom::IntAttribute::kActivedescendantId, 5);
+ AXTreeUpdate update = initial_state;
+ update.node_id_to_clear = 2;
+ EXPECT_TRUE(tree.Unserialize(update));
+ EXPECT_EQ("ACTIVE_DESCENDANT_CHANGED on 3, RELATED_NODE_CHANGED on 3",
+ DumpEvents(&event_generator));
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_generated_tree_unittest.cc b/chromium/ui/accessibility/ax_generated_tree_unittest.cc
index 3c58c9b40ef..8ec2979cb46 100644
--- a/chromium/ui/accessibility/ax_generated_tree_unittest.cc
+++ b/chromium/ui/accessibility/ax_generated_tree_unittest.cc
@@ -4,7 +4,7 @@
#include <memory>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_node.h"
@@ -62,7 +62,7 @@ TEST(AXGeneratedTreeTest, TestTreeGeneratorNoPermutations) {
};
int n = generator.UniqueTreeCount();
- ASSERT_EQ(static_cast<int>(arraysize(EXPECTED_TREES)), n);
+ ASSERT_EQ(static_cast<int>(base::size(EXPECTED_TREES)), n);
for (int i = 0; i < n; ++i) {
AXTree tree;
@@ -96,7 +96,7 @@ TEST(AXGeneratedTreeTest, TestTreeGeneratorWithPermutations) {
};
int n = generator.UniqueTreeCount();
- ASSERT_EQ(static_cast<int>(arraysize(EXPECTED_TREES)), n);
+ ASSERT_EQ(static_cast<int>(base::size(EXPECTED_TREES)), n);
for (int i = 0; i < n; i++) {
AXTree tree;
diff --git a/chromium/ui/accessibility/ax_language_info_unittest.cc b/chromium/ui/accessibility/ax_language_info_unittest.cc
index 1b01ce047f0..f2d9b7a490c 100644
--- a/chromium/ui/accessibility/ax_language_info_unittest.cc
+++ b/chromium/ui/accessibility/ax_language_info_unittest.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "ui/accessibility/ax_language_info.h"
+#include "base/command_line.h"
+#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_tree.h"
@@ -15,14 +17,25 @@
namespace ui {
+TEST(AXLanguageInfoTest, TestSwitch) {
+ // TODO(crbug/889370): Remove this test once this feature is stable
+ EXPECT_FALSE(
+ ::switches::AreExperimentalAccessibilityLanguageDetectionEnabled());
+
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ ::switches::kEnableExperimentalAccessibilityLanguageDetection);
+
+ EXPECT_TRUE(
+ ::switches::AreExperimentalAccessibilityLanguageDetectionEnabled());
+}
+
// 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
- */
+ // 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);
@@ -67,4 +80,151 @@ TEST(AXLanguageInfoTest, TestGetLanguageNoLangAttr) {
EXPECT_EQ(item4_lang, "");
}
+TEST(AXLanguageInfoTest, TestGetLanguageLangAttrInheritance) {
+ // 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
+ // 5
+ //
+ // 1 - English
+ // 2 - French
+ // all other nodes are unspecified
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(5);
+ 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[0].AddStringAttribute(
+ ax::mojom::StringAttribute::kLanguage, "en");
+ 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[1].AddStringAttribute(
+ ax::mojom::StringAttribute::kLanguage, "fr");
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[3].id = 4;
+ initial_state.nodes[3].child_ids.resize(1);
+ initial_state.nodes[3].child_ids[0] = 5;
+ initial_state.nodes[4].id = 5;
+ AXTree tree(initial_state);
+
+ AXNode* item1 = tree.GetFromId(1);
+ std::string item1_lang = item1->GetLanguage();
+ EXPECT_EQ(item1_lang, "en");
+
+ AXNode* item2 = tree.GetFromId(2);
+ std::string item2_lang = item2->GetLanguage();
+ EXPECT_EQ(item2_lang, "fr");
+
+ AXNode* item3 = tree.GetFromId(3);
+ std::string item3_lang = item3->GetLanguage();
+ EXPECT_EQ(item3_lang, "en");
+
+ AXNode* item4 = tree.GetFromId(4);
+ std::string item4_lang = item4->GetLanguage();
+ EXPECT_EQ(item4_lang, "fr");
+
+ AXNode* item5 = tree.GetFromId(5);
+ std::string item5_lang = item5->GetLanguage();
+ EXPECT_EQ(item5_lang, "fr");
+}
+
+TEST(AXLanguageInfoTest, TestGetLanguageLangDetection) {
+ // 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
+ // 5
+ //
+ // 1 - English lang attribute, no text
+ // 2 - French lang attribute, no text
+ // 3 - no attribute, French text
+ // 4 - no attribute, English text
+ // 5 - no attribute, German text
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(5);
+
+ {
+ AXNodeData& node1 = initial_state.nodes[0];
+ node1.id = 1;
+ node1.child_ids.resize(2);
+ node1.child_ids[0] = 2;
+ node1.child_ids[1] = 3;
+ node1.AddStringAttribute(ax::mojom::StringAttribute::kLanguage, "en");
+ }
+
+ {
+ AXNodeData& node2 = initial_state.nodes[1];
+ node2.id = 2;
+ node2.child_ids.resize(1);
+ node2.child_ids[0] = 4;
+ node2.AddStringAttribute(ax::mojom::StringAttribute::kLanguage, "fr");
+ }
+
+ {
+ AXNodeData& node3 = initial_state.nodes[2];
+ node3.id = 3;
+ node3.role = ax::mojom::Role::kStaticText;
+ std::string node3_text =
+ "Ce texte a été créé avec Google Translate, il est peu probable qu'il "
+ "soit idiomatique dans la langue cible indiquée Ce texte est "
+ "uniquement utilisé pour tester la détection de la langue.";
+ node3.AddStringAttribute(ax::mojom::StringAttribute::kName, node3_text);
+ }
+
+ {
+ AXNodeData& node4 = initial_state.nodes[3];
+ node4.id = 4;
+ node4.child_ids.resize(1);
+ node4.child_ids[0] = 5;
+ node4.role = ax::mojom::Role::kStaticText;
+ std::string node4_text =
+ "This is text created using Google Translate, it is unlikely to be "
+ "idomatic in the given target langauge. This text is only used to test "
+ "language detection";
+ node4.AddStringAttribute(ax::mojom::StringAttribute::kName, node4_text);
+ }
+
+ {
+ AXNodeData& node5 = initial_state.nodes[4];
+ node5.id = 5;
+ node5.role = ax::mojom::Role::kStaticText;
+ std::string node5_text =
+ "Dies ist ein mit Google Translate erstellter Text. Es ist "
+ "unwahrscheinlich, dass er in der angegebenen Zielsprache idiomatisch "
+ "ist. Dieser Text wird nur zum Testen der Spracherkennung verwendet.";
+ node5.AddStringAttribute(ax::mojom::StringAttribute::kName, node5_text);
+ }
+
+ AXTree tree(initial_state);
+
+ // TODO(crbug/889370): these expectations will be wrong once we detect
+ // language from the text.
+ AXNode* item1 = tree.GetFromId(1);
+ std::string item1_lang = item1->GetLanguage();
+ EXPECT_EQ(item1_lang, "en");
+
+ AXNode* item2 = tree.GetFromId(2);
+ std::string item2_lang = item2->GetLanguage();
+ EXPECT_EQ(item2_lang, "fr");
+
+ AXNode* item3 = tree.GetFromId(3);
+ std::string item3_lang = item3->GetLanguage();
+ EXPECT_EQ(item3_lang, "en");
+
+ AXNode* item4 = tree.GetFromId(4);
+ std::string item4_lang = item4->GetLanguage();
+ EXPECT_EQ(item4_lang, "fr");
+
+ AXNode* item5 = tree.GetFromId(5);
+ std::string item5_lang = item5->GetLanguage();
+ EXPECT_EQ(item5_lang, "fr");
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_mode_observer.h b/chromium/ui/accessibility/ax_mode_observer.h
index 1f2f2afa18a..36127ef8523 100644
--- a/chromium/ui/accessibility/ax_mode_observer.h
+++ b/chromium/ui/accessibility/ax_mode_observer.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_ACCESSIBILITY_PLATFORM_AX_MODE_OBSERVER_H_
-#define UI_ACCESSIBILITY_PLATFORM_AX_MODE_OBSERVER_H_
+#ifndef UI_ACCESSIBILITY_AX_MODE_OBSERVER_H_
+#define UI_ACCESSIBILITY_AX_MODE_OBSERVER_H_
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_mode.h"
@@ -20,4 +20,4 @@ class AX_EXPORT AXModeObserver {
} // namespace ui
-#endif // UI_ACCESSIBILITY_PLATFORM_AX_MODE_OBSERVER_H_
+#endif // UI_ACCESSIBILITY_AX_MODE_OBSERVER_H_
diff --git a/chromium/ui/accessibility/ax_node.cc b/chromium/ui/accessibility/ax_node.cc
index c245a1b42ba..0a3e1d90799 100644
--- a/chromium/ui/accessibility/ax_node.cc
+++ b/chromium/ui/accessibility/ax_node.cc
@@ -28,10 +28,7 @@ AXNode::AXNode(AXNode::OwnerTree* tree,
data_.id = id;
}
-AXNode::~AXNode() {
- if (language_info_)
- delete language_info_;
-}
+AXNode::~AXNode() = default;
int AXNode::GetUnignoredChildCount() const {
int count = 0;
@@ -45,6 +42,10 @@ int AXNode::GetUnignoredChildCount() const {
return count;
}
+AXNodeData&& AXNode::TakeData() {
+ return std::move(data_);
+}
+
AXNode* AXNode::GetUnignoredChildAtIndex(int index) const {
int count = 0;
for (int i = 0; i < child_count(); i++) {
@@ -184,15 +185,15 @@ base::string16 AXNode::GetInheritedString16Attribute(
const AXLanguageInfo* AXNode::GetLanguageInfo() {
if (language_info_)
- return language_info_;
+ return language_info_.get();
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_;
+ language_info_.reset(new AXLanguageInfo(this, lang_attr));
+ return language_info_.get();
}
// Try search for language through parent instead.
@@ -204,8 +205,8 @@ const AXLanguageInfo* AXNode::GetLanguageInfo() {
return nullptr;
// Cache the results on this node.
- language_info_ = new AXLanguageInfo(parent_lang_info, this);
- return language_info_;
+ language_info_.reset(new AXLanguageInfo(parent_lang_info, this));
+ return language_info_.get();
}
std::string AXNode::GetLanguage() {
@@ -347,12 +348,46 @@ bool AXNode::IsTableRow() const {
}
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;
+ if (!IsTableRow())
+ return 0;
+
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return 0;
+
+ const auto& iter = table_info->row_id_to_index.find(id());
+ if (iter != table_info->row_id_to_index.end())
+ return iter->second;
+ return 0;
}
+#if defined(OS_MACOSX)
+//
+// Table column-like nodes. These nodes are only present on macOS.
+//
+
+bool AXNode::IsTableColumn() const {
+ return data().role == ax::mojom::Role::kColumn;
+}
+
+int32_t AXNode::GetTableColColIndex() const {
+ if (!IsTableColumn())
+ return 0;
+
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return 0;
+
+ int32_t index = 0;
+ for (const AXNode* node : table_info->extra_mac_nodes) {
+ if (node == this)
+ break;
+ index++;
+ }
+ return index;
+}
+#endif // defined(OS_MACOSX)
+
//
// Table cell-like nodes.
//
@@ -515,218 +550,120 @@ void AXNode::IdVectorToNodeVector(std::vector<int32_t>& ids,
}
}
-// 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;
+// Uses function in ax_role_properties to check if node is item-like.
+bool AXNode::IsOrderedSetItem() const {
+ return ui::IsItemLike(data().role);
+}
+// Uses function in ax_role_properties to check if node is oredered-set-like.
+bool AXNode::IsOrderedSet() const {
+ return ui::IsSetLike(data().role);
+}
- default:
- return false;
+// pos_in_set and set_size related functions.
+// Uses AXTree's cache to calculate node's pos_in_set.
+int32_t AXNode::GetPosInSet() {
+ // Only allow this to be called on nodes that can hold pos_in_set values,
+ // which are defined in the ARIA spec.
+ if (!IsOrderedSetItem()) {
+ return 0;
}
+
+ const AXNode* ordered_set = GetOrderedSet();
+ if (!ordered_set) {
+ return 0;
+ }
+
+ // See AXTree::GetPosInSet
+ return tree_->GetPosInSet(*this, ordered_set);
}
-// Returns true if a node's role matches with the role of its container.
+// Uses AXTree's cache to calculate node's set_size.
+int32_t AXNode::GetSetSize() {
+ // Only allow this to be called on nodes that can hold set_size values, which
+ // are defined in the ARIA spec.
+ if (!(IsOrderedSetItem() || IsOrderedSet()))
+ return 0;
+
+ // If node is item-like, find its outerlying ordered set. Otherwise,
+ // this node is the ordered set.
+ const AXNode* ordered_set = this;
+ if (IsItemLike(data().role))
+ ordered_set = GetOrderedSet();
+ if (!ordered_set)
+ return 0;
+
+ // See AXTree::GetSetSize
+ return tree_->GetSetSize(*this, ordered_set);
+}
+
+// Returns true if the role of ordered set matches the role of item.
// 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;
+bool AXNode::SetRoleMatchesItemRole(const AXNode* ordered_set) const {
+ ax::mojom::Role item_role = data().role;
+
+ // Switch on role of ordered set
+ switch (ordered_set->data().role) {
+ case ax::mojom::Role::kFeed:
+ return item_role == ax::mojom::Role::kArticle;
+
+ case ax::mojom::Role::kList:
+ return item_role == ax::mojom::Role::kListItem;
+
+ case ax::mojom::Role::kGroup:
+ return item_role == ax::mojom::Role::kListItem ||
+ item_role == ax::mojom::Role::kMenuItem ||
+ item_role == ax::mojom::Role::kMenuItemRadio ||
+ item_role == ax::mojom::Role::kTreeItem;
- case ax::mojom::Role::kListItem:
- return container_role == ax::mojom::Role::kList ||
- container_role == ax::mojom::Role::kGroup;
+ case ax::mojom::Role::kMenu:
+ return item_role == ax::mojom::Role::kMenuItem ||
+ item_role == ax::mojom::Role::kMenuItemRadio ||
+ item_role == ax::mojom::Role::kMenuItemCheckBox;
- 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::kMenuBar:
+ return item_role == ax::mojom::Role::kMenuItem ||
+ item_role == ax::mojom::Role::kMenuItemRadio ||
+ item_role == ax::mojom::Role::kMenuItemCheckBox;
- 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::kTabList:
+ return item_role == ax::mojom::Role::kTab;
- case ax::mojom::Role::kTab:
- return container_role == ax::mojom::Role::kTabList;
+ case ax::mojom::Role::kTree:
+ return item_role == ax::mojom::Role::kTreeItem;
- case ax::mojom::Role::kMenuItemCheckBox:
- return container_role == ax::mojom::Role::kMenu ||
- container_role == ax::mojom::Role::kMenuBar;
+ case ax::mojom::Role::kListBox:
+ return item_role == ax::mojom::Role::kListBoxOption;
- case ax::mojom::Role::kTreeItem:
- return container_role == ax::mojom::Role::kTree ||
- container_role == ax::mojom::Role::kGroup;
+ case ax::mojom::Role::kMenuListPopup:
+ return item_role == ax::mojom::Role::kMenuListOption;
- case ax::mojom::Role::kListBoxOption:
- return container_role == ax::mojom::Role::kListBox;
+ case ax::mojom::Role::kRadioGroup:
+ return item_role == ax::mojom::Role::kRadioButton;
- case ax::mojom::Role::kRadioButton:
- return container_role == ax::mojom::Role::kRadioGroup;
+ case ax::mojom::Role::kDescriptionList:
+ // Only the term for each description list entry should receive posinset
+ // and setsize.
+ return item_role == ax::mojom::Role::kDescriptionListTerm ||
+ item_role == ax::mojom::Role::kTerm;
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 {
+// Finds ordered set that immediately contains node.
+// Is not required for set's role to match node's role.
+AXNode* AXNode::GetOrderedSet() 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) {
+ 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 8b9c5ca4dda..63836501b9f 100644
--- a/chromium/ui/accessibility/ax_node.h
+++ b/chromium/ui/accessibility/ax_node.h
@@ -7,9 +7,11 @@
#include <stdint.h>
+#include <memory>
#include <ostream>
#include <vector>
+#include "build/build_config.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_node_data.h"
@@ -31,6 +33,11 @@ class AX_EXPORT AXNode final {
virtual AXTableInfo* GetTableInfo(const AXNode* table_node) const = 0;
// See AXTree.
virtual AXNode* GetFromId(int32_t id) const = 0;
+
+ virtual int32_t GetPosInSet(const AXNode& node,
+ const AXNode* ordered_set) = 0;
+ virtual int32_t GetSetSize(const AXNode& node,
+ const AXNode* ordered_set) = 0;
};
// The constructor requires a parent, id, and index in parent, but
@@ -48,6 +55,9 @@ class AX_EXPORT AXNode final {
const std::vector<AXNode*>& children() const { return children_; }
int index_in_parent() const { return index_in_parent_; }
+ // Returns ownership of |data_| to the caller; effectively clearing |data_|.
+ AXNodeData&& TakeData();
+
// Get the child at the given index.
AXNode* ChildAtIndex(int index) const { return children_[index]; }
@@ -182,10 +192,17 @@ class AX_EXPORT AXNode final {
return data().GetHtmlAttribute(attribute, value);
}
- // PosInSet and SetSize public methods
+ // PosInSet and SetSize public methods.
+ bool IsOrderedSetItem() const;
+ bool IsOrderedSet() const;
int32_t GetPosInSet();
int32_t GetSetSize();
+ // Helpers for GetPosInSet and GetSetSize.
+ // Returns true if the role of ordered set matches the role of item.
+ // Returns false otherwise.
+ bool SetRoleMatchesItemRole(const AXNode* ordered_set) const;
+
const std::string& GetInheritedStringAttribute(
ax::mojom::StringAttribute attribute) const;
base::string16 GetInheritedString16Attribute(
@@ -238,6 +255,12 @@ class AX_EXPORT AXNode final {
bool IsTableRow() const;
int32_t GetTableRowRowIndex() const;
+#if defined(OS_MACOSX)
+ // Table column-like nodes. These nodes are only present on macOS.
+ bool IsTableColumn() const;
+ int32_t GetTableColColIndex() const;
+#endif // defined(OS_MACOSX)
+
// Table cell-like nodes.
bool IsTableCellOrHeader() const;
int32_t GetTableCellIndex() const;
@@ -261,21 +284,8 @@ class AX_EXPORT AXNode final {
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);
+ // Finds and returns a pointer to ordered set containing node.
+ AXNode* GetOrderedSet() const;
OwnerTree* tree_; // Owns this.
int index_in_parent_;
@@ -283,7 +293,7 @@ class AX_EXPORT AXNode final {
std::vector<AXNode*> children_;
AXNodeData data_;
- AXLanguageInfo* language_info_;
+ std::unique_ptr<AXLanguageInfo> language_info_;
// Return an object containing information about the languages used.
// Will walk up tree if needed to determine language.
diff --git a/chromium/ui/accessibility/ax_node_data.cc b/chromium/ui/accessibility/ax_node_data.cc
index 7dfeb25678c..b7b1928eea8 100644
--- a/chromium/ui/accessibility/ax_node_data.cc
+++ b/chromium/ui/accessibility/ax_node_data.cc
@@ -209,6 +209,22 @@ AXNodeData::AXNodeData(const AXNodeData& other) {
relative_bounds = other.relative_bounds;
}
+AXNodeData::AXNodeData(AXNodeData&& other) {
+ id = other.id;
+ role = other.role;
+ state = other.state;
+ actions = other.actions;
+ string_attributes.swap(other.string_attributes);
+ int_attributes.swap(other.int_attributes);
+ float_attributes.swap(other.float_attributes);
+ bool_attributes.swap(other.bool_attributes);
+ intlist_attributes.swap(other.intlist_attributes);
+ stringlist_attributes.swap(other.stringlist_attributes);
+ html_attributes.swap(other.html_attributes);
+ child_ids.swap(other.child_ids);
+ relative_bounds = other.relative_bounds;
+}
+
AXNodeData& AXNodeData::operator=(AXNodeData other) {
id = other.id;
role = other.role;
@@ -413,41 +429,96 @@ bool AXNodeData::GetHtmlAttribute(
void AXNodeData::AddStringAttribute(ax::mojom::StringAttribute attribute,
const std::string& value) {
+ DCHECK_NE(attribute, ax::mojom::StringAttribute::kNone);
+ if (HasStringAttribute(attribute))
+ RemoveStringAttribute(attribute);
string_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::AddIntAttribute(ax::mojom::IntAttribute attribute, int value) {
+ DCHECK_NE(attribute, ax::mojom::IntAttribute::kNone);
+ if (HasIntAttribute(attribute))
+ RemoveIntAttribute(attribute);
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) {
+ DCHECK_NE(attribute, ax::mojom::FloatAttribute::kNone);
+ if (HasFloatAttribute(attribute))
+ RemoveFloatAttribute(attribute);
float_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::AddBoolAttribute(ax::mojom::BoolAttribute attribute,
bool value) {
+ DCHECK_NE(attribute, ax::mojom::BoolAttribute::kNone);
+ if (HasBoolAttribute(attribute))
+ RemoveBoolAttribute(attribute);
bool_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::AddIntListAttribute(ax::mojom::IntListAttribute attribute,
const std::vector<int32_t>& value) {
+ DCHECK_NE(attribute, ax::mojom::IntListAttribute::kNone);
+ if (HasIntListAttribute(attribute))
+ RemoveIntListAttribute(attribute);
intlist_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::AddStringListAttribute(
ax::mojom::StringListAttribute attribute,
const std::vector<std::string>& value) {
+ DCHECK_NE(attribute, ax::mojom::StringListAttribute::kNone);
+ if (HasStringListAttribute(attribute))
+ RemoveStringListAttribute(attribute);
stringlist_attributes.push_back(std::make_pair(attribute, value));
}
+void AXNodeData::RemoveStringAttribute(ax::mojom::StringAttribute attribute) {
+ DCHECK_NE(attribute, ax::mojom::StringAttribute::kNone);
+ base::EraseIf(string_attributes, [attribute](const auto& string_attribute) {
+ return string_attribute.first == attribute;
+ });
+}
+
+void AXNodeData::RemoveIntAttribute(ax::mojom::IntAttribute attribute) {
+ DCHECK_NE(attribute, ax::mojom::IntAttribute::kNone);
+ base::EraseIf(int_attributes, [attribute](const auto& int_attribute) {
+ return int_attribute.first == attribute;
+ });
+}
+
+void AXNodeData::RemoveFloatAttribute(ax::mojom::FloatAttribute attribute) {
+ DCHECK_NE(attribute, ax::mojom::FloatAttribute::kNone);
+ base::EraseIf(float_attributes, [attribute](const auto& float_attribute) {
+ return float_attribute.first == attribute;
+ });
+}
+
+void AXNodeData::RemoveBoolAttribute(ax::mojom::BoolAttribute attribute) {
+ DCHECK_NE(attribute, ax::mojom::BoolAttribute::kNone);
+ base::EraseIf(bool_attributes, [attribute](const auto& bool_attribute) {
+ return bool_attribute.first == attribute;
+ });
+}
+
+void AXNodeData::RemoveIntListAttribute(ax::mojom::IntListAttribute attribute) {
+ DCHECK_NE(attribute, ax::mojom::IntListAttribute::kNone);
+ base::EraseIf(intlist_attributes, [attribute](const auto& intlist_attribute) {
+ return intlist_attribute.first == attribute;
+ });
+}
+
+void AXNodeData::RemoveStringListAttribute(
+ ax::mojom::StringListAttribute attribute) {
+ DCHECK_NE(attribute, ax::mojom::StringListAttribute::kNone);
+ base::EraseIf(stringlist_attributes,
+ [attribute](const auto& stringlist_attribute) {
+ return stringlist_attribute.first == attribute;
+ });
+}
+
void AXNodeData::SetName(const std::string& name) {
auto iter = std::find_if(string_attributes.begin(), string_attributes.end(),
[](const auto& string_attribute) {
@@ -1048,7 +1119,7 @@ std::string AXNodeData::ToString() const {
result += " autocomplete=" + value;
break;
case ax::mojom::StringAttribute::kChildTreeId:
- result += " child_tree_id=" + value;
+ result += " child_tree_id=" + value.substr(0, 8);
break;
case ax::mojom::StringAttribute::kClassName:
result += " class_name=" + value;
diff --git a/chromium/ui/accessibility/ax_node_data.h b/chromium/ui/accessibility/ax_node_data.h
index 232d56208f0..9762ed1bb2b 100644
--- a/chromium/ui/accessibility/ax_node_data.h
+++ b/chromium/ui/accessibility/ax_node_data.h
@@ -37,6 +37,7 @@ struct AX_EXPORT AXNodeData {
virtual ~AXNodeData();
AXNodeData(const AXNodeData& other);
+ AXNodeData(AXNodeData&& other);
AXNodeData& operator=(AXNodeData other);
// Accessing accessibility attributes:
@@ -93,11 +94,17 @@ struct AX_EXPORT AXNodeData {
bool GetHtmlAttribute(const char* attribute, base::string16* value) const;
bool GetHtmlAttribute(const char* attribute, std::string* value) const;
+ //
// Setting accessibility attributes.
+ //
+ // Replaces an attribute if not present. This is safer than crashing via a
+ // DCHECK or doing nothing, because most likely that's what the caller would
+ // have wanted or what existing code already assumes.
+ //
+
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,
@@ -106,6 +113,17 @@ struct AX_EXPORT AXNodeData {
const std::vector<std::string>& value);
//
+ // Removing accessibility attributes.
+ //
+
+ void RemoveStringAttribute(ax::mojom::StringAttribute attribute);
+ void RemoveIntAttribute(ax::mojom::IntAttribute attribute);
+ void RemoveFloatAttribute(ax::mojom::FloatAttribute attribute);
+ void RemoveBoolAttribute(ax::mojom::BoolAttribute attribute);
+ void RemoveIntListAttribute(ax::mojom::IntListAttribute attribute);
+ void RemoveStringListAttribute(ax::mojom::StringListAttribute attribute);
+
+ //
// Convenience functions.
//
diff --git a/chromium/ui/accessibility/ax_node_position_unittest.cc b/chromium/ui/accessibility/ax_node_position_unittest.cc
index 5aeeff01fa3..f1b8e810ea6 100644
--- a/chromium/ui/accessibility/ax_node_position_unittest.cc
+++ b/chromium/ui/accessibility/ax_node_position_unittest.cc
@@ -201,7 +201,7 @@ void AXPositionTest::SetUp() {
initial_state.nodes.push_back(static_text2_);
initial_state.nodes.push_back(inline_box2_);
initial_state.has_tree_data = true;
- initial_state.tree_data.tree_id = AXTreeID::FromString("0");
+ initial_state.tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
initial_state.tree_data.title = "Dialog title";
AXSerializableTree src_tree(initial_state);
@@ -1691,22 +1691,22 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=6 "
+ {"TextPosition anchor_id=1 text_offset=6 "
"affinity=downstream annotated_text=Button<C>heck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=12 "
+ "TextPosition anchor_id=1 text_offset=12 "
"affinity=downstream annotated_text=ButtonCheck <b>oxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=downstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=20 "
+ "TextPosition anchor_id=1 text_offset=20 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"<1>\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ "TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=27 "
+ "TextPosition anchor_id=1 text_offset=27 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine <2>",
"NullPosition"}},
@@ -1716,11 +1716,11 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=5 "
+ {"TextPosition anchor_id=4 text_offset=5 "
"affinity=downstream annotated_text=Line <1>\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ "TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=12 "
+ "TextPosition anchor_id=4 text_offset=12 "
"affinity=downstream annotated_text=Line 1\nLine <2>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -1729,11 +1729,11 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=5 "
+ {"TextPosition anchor_id=5 text_offset=5 "
"affinity=downstream annotated_text=Line <1>",
- "TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ "TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
- "TextPosition tree_id=0 anchor_id=9 text_offset=5 "
+ "TextPosition anchor_id=9 text_offset=5 "
"affinity=downstream annotated_text=Line <2>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -1742,7 +1742,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=5 "
+ {"TextPosition anchor_id=9 text_offset=5 "
"affinity=downstream annotated_text=Line <2>",
"NullPosition"}}));
@@ -1756,25 +1756,25 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=6 "
+ {"TextPosition anchor_id=1 text_offset=6 "
"affinity=downstream annotated_text=Button<C>heck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=12 "
+ "TextPosition anchor_id=1 text_offset=12 "
"affinity=downstream annotated_text=ButtonCheck <b>oxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=downstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=20 "
+ "TextPosition anchor_id=1 text_offset=20 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"<1>\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ "TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=27 "
+ "TextPosition anchor_id=1 text_offset=27 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine <2>",
- "TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ "TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -1783,13 +1783,13 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=5 "
+ {"TextPosition anchor_id=4 text_offset=5 "
"affinity=downstream annotated_text=Line <1>\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ "TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=12 "
+ "TextPosition anchor_id=4 text_offset=12 "
"affinity=downstream annotated_text=Line 1\nLine <2>",
- "TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ "TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextWordStartPosition(
@@ -1797,9 +1797,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=5 "
+ {"TextPosition anchor_id=5 text_offset=5 "
"affinity=downstream annotated_text=Line <1>",
- "TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ "TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextWordStartPosition(
@@ -1807,9 +1807,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=5 "
+ {"TextPosition anchor_id=9 text_offset=5 "
"affinity=downstream annotated_text=Line <2>",
- "TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ "TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>"}}));
INSTANTIATE_TEST_CASE_P(
@@ -1822,10 +1822,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ {"TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -1834,9 +1834,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ {"TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextWordStartPosition(
@@ -1844,9 +1844,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=5 "
+ {"TextPosition anchor_id=5 text_offset=5 "
"affinity=downstream annotated_text=Line <1>",
- "TextPosition tree_id=0 anchor_id=5 text_offset=5 "
+ "TextPosition anchor_id=5 text_offset=5 "
"affinity=downstream annotated_text=Line <1>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextWordStartPosition(
@@ -1854,9 +1854,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=5 "
+ {"TextPosition anchor_id=9 text_offset=5 "
"affinity=downstream annotated_text=Line <2>",
- "TextPosition tree_id=0 anchor_id=9 text_offset=5 "
+ "TextPosition anchor_id=9 text_offset=5 "
"affinity=downstream annotated_text=Line <2>"}}));
INSTANTIATE_TEST_CASE_P(
@@ -1869,25 +1869,25 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=27 "
+ {"TextPosition anchor_id=1 text_offset=27 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine <2>",
- "TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ "TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=20 "
+ "TextPosition anchor_id=1 text_offset=20 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"<1>\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=downstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=12 "
+ "TextPosition anchor_id=1 text_offset=12 "
"affinity=downstream annotated_text=ButtonCheck <b>oxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=6 "
+ "TextPosition anchor_id=1 text_offset=6 "
"affinity=downstream annotated_text=Button<C>heck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2",
"NullPosition"}},
@@ -1897,19 +1897,19 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=12 "
+ {"TextPosition anchor_id=4 text_offset=12 "
"affinity=downstream annotated_text=Line 1\nLine <2>",
- "TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ "TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=5 "
+ "TextPosition anchor_id=4 text_offset=5 "
"affinity=downstream annotated_text=Line <1>\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2",
- "TextPosition tree_id=0 anchor_id=3 text_offset=6 "
+ "TextPosition anchor_id=3 text_offset=6 "
"affinity=downstream annotated_text=Check <b>ox",
- "TextPosition tree_id=0 anchor_id=3 text_offset=0 "
+ "TextPosition anchor_id=3 text_offset=0 "
"affinity=downstream annotated_text=<C>heck box",
- "TextPosition tree_id=0 anchor_id=2 text_offset=0 "
+ "TextPosition anchor_id=2 text_offset=0 "
"affinity=downstream annotated_text=<B>utton",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -1918,13 +1918,13 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ {"TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1",
- "TextPosition tree_id=0 anchor_id=3 text_offset=6 "
+ "TextPosition anchor_id=3 text_offset=6 "
"affinity=downstream annotated_text=Check <b>ox",
- "TextPosition tree_id=0 anchor_id=3 text_offset=0 "
+ "TextPosition anchor_id=3 text_offset=0 "
"affinity=downstream annotated_text=<C>heck box",
- "TextPosition tree_id=0 anchor_id=2 text_offset=0 "
+ "TextPosition anchor_id=2 text_offset=0 "
"affinity=downstream annotated_text=<B>utton",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -1933,17 +1933,17 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
- "TextPosition tree_id=0 anchor_id=6 text_offset=5 "
+ "TextPosition anchor_id=6 text_offset=5 "
"affinity=downstream annotated_text=Line <1>",
- "TextPosition tree_id=0 anchor_id=6 text_offset=0 "
+ "TextPosition anchor_id=6 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1",
- "TextPosition tree_id=0 anchor_id=3 text_offset=6 "
+ "TextPosition anchor_id=3 text_offset=6 "
"affinity=downstream annotated_text=Check <b>ox",
- "TextPosition tree_id=0 anchor_id=3 text_offset=0 "
+ "TextPosition anchor_id=3 text_offset=0 "
"affinity=downstream annotated_text=<C>heck box",
- "TextPosition tree_id=0 anchor_id=2 text_offset=0 "
+ "TextPosition anchor_id=2 text_offset=0 "
"affinity=downstream annotated_text=<B>utton",
"NullPosition"}}));
@@ -1957,28 +1957,28 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=27 "
+ {"TextPosition anchor_id=1 text_offset=27 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine <2>",
- "TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ "TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=20 "
+ "TextPosition anchor_id=1 text_offset=20 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"<1>\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=downstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=12 "
+ "TextPosition anchor_id=1 text_offset=12 "
"affinity=downstream annotated_text=ButtonCheck <b>oxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=6 "
+ "TextPosition anchor_id=1 text_offset=6 "
"affinity=downstream annotated_text=Button<C>heck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -1987,15 +1987,15 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=12 "
+ {"TextPosition anchor_id=4 text_offset=12 "
"affinity=downstream annotated_text=Line 1\nLine <2>",
- "TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ "TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=5 "
+ "TextPosition anchor_id=4 text_offset=5 "
"affinity=downstream annotated_text=Line <1>\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousWordStartPosition(
@@ -2003,9 +2003,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ {"TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1",
- "TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ "TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousWordStartPosition(
@@ -2013,9 +2013,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
- "TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ "TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2028,10 +2028,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=27 "
+ {"TextPosition anchor_id=1 text_offset=27 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine <2>",
- "TextPosition tree_id=0 anchor_id=1 text_offset=27 "
+ "TextPosition anchor_id=1 text_offset=27 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine <2>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2040,9 +2040,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=12 "
+ {"TextPosition anchor_id=4 text_offset=12 "
"affinity=downstream annotated_text=Line 1\nLine <2>",
- "TextPosition tree_id=0 anchor_id=4 text_offset=12 "
+ "TextPosition anchor_id=4 text_offset=12 "
"affinity=downstream annotated_text=Line 1\nLine <2>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousWordStartPosition(
@@ -2050,7 +2050,7 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=5 "
+ {"TextPosition anchor_id=5 text_offset=5 "
"affinity=downstream annotated_text=Line <1>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousWordStartPosition(
@@ -2058,9 +2058,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
- "TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ "TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2073,25 +2073,25 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=6 "
+ {"TextPosition anchor_id=1 text_offset=6 "
"affinity=downstream annotated_text=Button<C>heck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=11 "
+ "TextPosition anchor_id=1 text_offset=11 "
"affinity=downstream annotated_text=ButtonCheck< >boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=19 "
+ "TextPosition anchor_id=1 text_offset=19 "
"affinity=downstream annotated_text=ButtonCheck boxLine< "
">1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=26 "
+ "TextPosition anchor_id=1 text_offset=26 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine< >2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ "TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>",
"NullPosition"}},
@@ -2101,13 +2101,13 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=4 "
+ {"TextPosition anchor_id=4 text_offset=4 "
"affinity=downstream annotated_text=Line< >1\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ "TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=11 "
+ "TextPosition anchor_id=4 text_offset=11 "
"affinity=downstream annotated_text=Line 1\nLine< >2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ "TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2116,13 +2116,13 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=4 "
+ {"TextPosition anchor_id=5 text_offset=4 "
"affinity=downstream annotated_text=Line< >1",
- "TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ "TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>",
- "TextPosition tree_id=0 anchor_id=9 text_offset=4 "
+ "TextPosition anchor_id=9 text_offset=4 "
"affinity=downstream annotated_text=Line< >2",
- "TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ "TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2131,7 +2131,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ {"TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>",
"NullPosition"}}));
@@ -2145,28 +2145,28 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=6 "
+ {"TextPosition anchor_id=1 text_offset=6 "
"affinity=downstream annotated_text=Button<C>heck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=11 "
+ "TextPosition anchor_id=1 text_offset=11 "
"affinity=downstream annotated_text=ButtonCheck< >boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=19 "
+ "TextPosition anchor_id=1 text_offset=19 "
"affinity=downstream annotated_text=ButtonCheck boxLine< "
">1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=26 "
+ "TextPosition anchor_id=1 text_offset=26 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine< >2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ "TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>",
- "TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ "TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2175,15 +2175,15 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=4 "
+ {"TextPosition anchor_id=4 text_offset=4 "
"affinity=downstream annotated_text=Line< >1\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ "TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=11 "
+ "TextPosition anchor_id=4 text_offset=11 "
"affinity=downstream annotated_text=Line 1\nLine< >2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ "TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>",
- "TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ "TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextWordEndPosition(
@@ -2191,11 +2191,11 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=4 "
+ {"TextPosition anchor_id=5 text_offset=4 "
"affinity=downstream annotated_text=Line< >1",
- "TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ "TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>",
- "TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ "TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextWordEndPosition(
@@ -2203,9 +2203,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ {"TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>",
- "TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ "TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2218,10 +2218,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
7 /* text_offset after the first character of "Check". */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=11 "
+ {"TextPosition anchor_id=1 text_offset=11 "
"affinity=downstream annotated_text=ButtonCheck< >boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=11 "
+ "TextPosition anchor_id=1 text_offset=11 "
"affinity=downstream annotated_text=ButtonCheck< >boxLine "
"1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2230,9 +2230,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=4 "
+ {"TextPosition anchor_id=4 text_offset=4 "
"affinity=downstream annotated_text=Line< >1\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=4 "
+ "TextPosition anchor_id=4 text_offset=4 "
"affinity=downstream annotated_text=Line< >1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextWordEndPosition(
@@ -2240,9 +2240,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=4 "
+ {"TextPosition anchor_id=5 text_offset=4 "
"affinity=downstream annotated_text=Line< >1",
- "TextPosition tree_id=0 anchor_id=5 text_offset=4 "
+ "TextPosition anchor_id=5 text_offset=4 "
"affinity=downstream annotated_text=Line< >1"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextWordEndPosition(
@@ -2250,7 +2250,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=4 "
+ {"TextPosition anchor_id=9 text_offset=4 "
"affinity=downstream annotated_text=Line< >2"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2263,22 +2263,22 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=26 "
+ {"TextPosition anchor_id=1 text_offset=26 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine< >2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=19 "
+ "TextPosition anchor_id=1 text_offset=19 "
"affinity=downstream annotated_text=ButtonCheck boxLine< "
">1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=11 "
+ "TextPosition anchor_id=1 text_offset=11 "
"affinity=downstream annotated_text=ButtonCheck< >boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=6 "
+ "TextPosition anchor_id=1 text_offset=6 "
"affinity=downstream annotated_text=Button<C>heck boxLine "
"1\nLine 2",
"NullPosition"}},
@@ -2288,17 +2288,17 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=11 "
+ {"TextPosition anchor_id=4 text_offset=11 "
"affinity=downstream annotated_text=Line 1\nLine< >2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ "TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=4 "
+ "TextPosition anchor_id=4 text_offset=4 "
"affinity=downstream annotated_text=Line< >1\nLine 2",
- "TextPosition tree_id=0 anchor_id=3 text_offset=9 "
+ "TextPosition anchor_id=3 text_offset=9 "
"affinity=downstream annotated_text=Check box<>",
- "TextPosition tree_id=0 anchor_id=3 text_offset=5 "
+ "TextPosition anchor_id=3 text_offset=5 "
"affinity=downstream annotated_text=Check< >box",
- "TextPosition tree_id=0 anchor_id=2 text_offset=6 "
+ "TextPosition anchor_id=2 text_offset=6 "
"affinity=downstream annotated_text=Button<>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2307,13 +2307,13 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=4 "
+ {"TextPosition anchor_id=5 text_offset=4 "
"affinity=downstream annotated_text=Line< >1",
- "TextPosition tree_id=0 anchor_id=3 text_offset=9 "
+ "TextPosition anchor_id=3 text_offset=9 "
"affinity=downstream annotated_text=Check box<>",
- "TextPosition tree_id=0 anchor_id=3 text_offset=5 "
+ "TextPosition anchor_id=3 text_offset=5 "
"affinity=downstream annotated_text=Check< >box",
- "TextPosition tree_id=0 anchor_id=2 text_offset=6 "
+ "TextPosition anchor_id=2 text_offset=6 "
"affinity=downstream annotated_text=Button<>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2322,15 +2322,15 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=6 text_offset=6 "
+ {"TextPosition anchor_id=6 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>",
- "TextPosition tree_id=0 anchor_id=6 text_offset=4 "
+ "TextPosition anchor_id=6 text_offset=4 "
"affinity=downstream annotated_text=Line< >1",
- "TextPosition tree_id=0 anchor_id=3 text_offset=9 "
+ "TextPosition anchor_id=3 text_offset=9 "
"affinity=downstream annotated_text=Check box<>",
- "TextPosition tree_id=0 anchor_id=3 text_offset=5 "
+ "TextPosition anchor_id=3 text_offset=5 "
"affinity=downstream annotated_text=Check< >box",
- "TextPosition tree_id=0 anchor_id=2 text_offset=6 "
+ "TextPosition anchor_id=2 text_offset=6 "
"affinity=downstream annotated_text=Button<>",
"NullPosition"}}));
@@ -2344,25 +2344,25 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=26 "
+ {"TextPosition anchor_id=1 text_offset=26 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine< >2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=19 "
+ "TextPosition anchor_id=1 text_offset=19 "
"affinity=downstream annotated_text=ButtonCheck boxLine< "
">1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=11 "
+ "TextPosition anchor_id=1 text_offset=11 "
"affinity=downstream annotated_text=ButtonCheck< >boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=6 "
+ "TextPosition anchor_id=1 text_offset=6 "
"affinity=downstream annotated_text=Button<C>heck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2371,13 +2371,13 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=11 "
+ {"TextPosition anchor_id=4 text_offset=11 "
"affinity=downstream annotated_text=Line 1\nLine< >2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ "TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=4 "
+ "TextPosition anchor_id=4 text_offset=4 "
"affinity=downstream annotated_text=Line< >1\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousWordEndPosition(
@@ -2385,9 +2385,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=4 "
+ {"TextPosition anchor_id=5 text_offset=4 "
"affinity=downstream annotated_text=Line< >1",
- "TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ "TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousWordEndPosition(
@@ -2395,7 +2395,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2408,7 +2408,7 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ {"TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2417,7 +2417,7 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ {"TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousWordEndPosition(
@@ -2425,9 +2425,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=4 "
+ {"TextPosition anchor_id=5 text_offset=4 "
"affinity=downstream annotated_text=Line< >1",
- "TextPosition tree_id=0 anchor_id=5 text_offset=4 "
+ "TextPosition anchor_id=5 text_offset=4 "
"affinity=downstream annotated_text=Line< >1"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousWordEndPosition(
@@ -2435,7 +2435,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=4 "
+ {"TextPosition anchor_id=9 text_offset=4 "
"affinity=downstream annotated_text=Line< >2"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2448,10 +2448,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ {"TextPosition anchor_id=1 text_offset=15 "
"affinity=downstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ "TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
"NullPosition"}},
@@ -2461,7 +2461,7 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ {"TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2470,7 +2470,7 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2491,13 +2491,13 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ {"TextPosition anchor_id=1 text_offset=15 "
"affinity=downstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ "TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ "TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2506,9 +2506,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ {"TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ "TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextLineStartPosition(
@@ -2516,7 +2516,7 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ {"TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextLineStartPosition(
@@ -2524,7 +2524,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ {"TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2537,7 +2537,7 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ {"TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2546,7 +2546,7 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ {"TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextLineStartPosition(
@@ -2554,9 +2554,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
- "TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ "TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextLineStartPosition(
@@ -2576,13 +2576,13 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at the end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ {"TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=downstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2",
"NullPosition"}},
@@ -2592,11 +2592,11 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ {"TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2",
- "TextPosition tree_id=0 anchor_id=2 text_offset=0 "
+ "TextPosition anchor_id=2 text_offset=0 "
"affinity=downstream annotated_text=<B>utton",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2605,9 +2605,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ {"TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1",
- "TextPosition tree_id=0 anchor_id=2 text_offset=0 "
+ "TextPosition anchor_id=2 text_offset=0 "
"affinity=downstream annotated_text=<B>utton",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2616,11 +2616,11 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
- "TextPosition tree_id=0 anchor_id=6 text_offset=0 "
+ "TextPosition anchor_id=6 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1",
- "TextPosition tree_id=0 anchor_id=2 text_offset=0 "
+ "TextPosition anchor_id=2 text_offset=0 "
"affinity=downstream annotated_text=<B>utton",
"NullPosition"}}));
@@ -2634,16 +2634,16 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at the end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ {"TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=downstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2652,11 +2652,11 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ {"TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineStartPosition(
@@ -2664,9 +2664,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ {"TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1",
- "TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ "TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineStartPosition(
@@ -2674,9 +2674,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
- "TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ "TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2689,10 +2689,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at the end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ {"TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=22 "
+ "TextPosition anchor_id=1 text_offset=22 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\n<L>ine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2701,9 +2701,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ {"TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=7 "
+ "TextPosition anchor_id=4 text_offset=7 "
"affinity=downstream annotated_text=Line 1\n<L>ine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineStartPosition(
@@ -2711,9 +2711,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
5 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ {"TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1",
- "TextPosition tree_id=0 anchor_id=5 text_offset=0 "
+ "TextPosition anchor_id=5 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineStartPosition(
@@ -2721,9 +2721,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2",
- "TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ "TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2736,13 +2736,13 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ {"TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine 1"
"<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ "TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>",
"NullPosition"}},
@@ -2752,9 +2752,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ {"TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ "TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2763,9 +2763,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ {"TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>",
- "TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ "TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2774,7 +2774,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ {"TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>",
"NullPosition"}}));
@@ -2788,16 +2788,16 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ {"TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine 1"
"<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ "TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>",
- "TextPosition tree_id=0 anchor_id=1 text_offset=28 "
+ "TextPosition anchor_id=1 text_offset=28 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2806,11 +2806,11 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ {"TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ "TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>",
- "TextPosition tree_id=0 anchor_id=4 text_offset=13 "
+ "TextPosition anchor_id=4 text_offset=13 "
"affinity=downstream annotated_text=Line 1\nLine 2<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextLineEndPosition(
@@ -2818,9 +2818,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ {"TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>",
- "TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ "TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextLineEndPosition(
@@ -2828,9 +2828,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ {"TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>",
- "TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ "TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2843,10 +2843,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ {"TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ "TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2855,9 +2855,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ {"TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ "TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextLineEndPosition(
@@ -2865,9 +2865,9 @@ INSTANTIATE_TEST_CASE_P(
}),
STATIC_TEXT1_ID,
1 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ {"TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>",
- "TextPosition tree_id=0 anchor_id=5 text_offset=6 "
+ "TextPosition anchor_id=5 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreateNextLineEndPosition(
@@ -2875,9 +2875,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ {"TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>",
- "TextPosition tree_id=0 anchor_id=9 text_offset=6 "
+ "TextPosition anchor_id=9 text_offset=6 "
"affinity=downstream annotated_text=Line 2<>"}}));
INSTANTIATE_TEST_CASE_P(
@@ -2894,10 +2894,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ {"TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2906,9 +2906,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ {"TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ "TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineEndPosition(
@@ -2916,7 +2916,7 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
20 /* text_offset on the last character of "line 1". */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ {"TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
"NullPosition"}},
@@ -2926,7 +2926,7 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
5 /* text_offset on the last character of "Line 1". */,
- {"TextPosition tree_id=0 anchor_id=3 text_offset=9 "
+ {"TextPosition anchor_id=3 text_offset=9 "
"affinity=downstream annotated_text=Check box<>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2935,11 +2935,11 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=7 text_offset=0 "
+ {"TextPosition anchor_id=7 text_offset=0 "
"affinity=downstream annotated_text=<\n>",
- "TextPosition tree_id=0 anchor_id=6 text_offset=6 "
+ "TextPosition anchor_id=6 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>",
- "TextPosition tree_id=0 anchor_id=3 text_offset=9 "
+ "TextPosition anchor_id=3 text_offset=9 "
"affinity=downstream annotated_text=Check box<>",
"NullPosition"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2948,11 +2948,11 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=7 text_offset=0 "
+ {"TextPosition anchor_id=7 text_offset=0 "
"affinity=downstream annotated_text=<\n>",
- "TextPosition tree_id=0 anchor_id=6 text_offset=6 "
+ "TextPosition anchor_id=6 text_offset=6 "
"affinity=downstream annotated_text=Line 1<>",
- "TextPosition tree_id=0 anchor_id=3 text_offset=9 "
+ "TextPosition anchor_id=3 text_offset=9 "
"affinity=downstream annotated_text=Check box<>",
"NullPosition"}}));
@@ -2970,10 +2970,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
28 /* text_offset at end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ {"TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -2982,9 +2982,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
13 /* text_offset at end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ {"TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ "TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineEndPosition(
@@ -2992,10 +2992,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
20 /* text_offset on the last character of "line 1". */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=15 "
+ {"TextPosition anchor_id=1 text_offset=15 "
"affinity=upstream annotated_text=ButtonCheck box<L>ine "
"1\nLine 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=0 "
+ "TextPosition anchor_id=1 text_offset=0 "
"affinity=downstream annotated_text=<B>uttonCheck boxLine "
"1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -3004,9 +3004,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
5 /* text_offset on the last character of "Line 1". */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ {"TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=0 "
+ "TextPosition anchor_id=4 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineEndPosition(
@@ -3014,7 +3014,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineEndPosition(
@@ -3022,7 +3022,7 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=9 text_offset=0 "
+ {"TextPosition anchor_id=9 text_offset=0 "
"affinity=downstream annotated_text=<L>ine 2"}}));
INSTANTIATE_TEST_CASE_P(
@@ -3035,10 +3035,10 @@ INSTANTIATE_TEST_CASE_P(
}),
ROOT_ID,
27 /* text_offset one before the end of root. */,
- {"TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ {"TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=1 text_offset=21 "
+ "TextPosition anchor_id=1 text_offset=21 "
"affinity=downstream annotated_text=ButtonCheck boxLine "
"1<\n>Line 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
@@ -3047,9 +3047,9 @@ INSTANTIATE_TEST_CASE_P(
}),
TEXT_FIELD_ID,
12 /* text_offset one before the end of text field */,
- {"TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ {"TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2",
- "TextPosition tree_id=0 anchor_id=4 text_offset=6 "
+ "TextPosition anchor_id=4 text_offset=6 "
"affinity=downstream annotated_text=Line 1<\n>Line 2"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineEndPosition(
@@ -3057,9 +3057,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
4 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=7 text_offset=0 "
+ {"TextPosition anchor_id=7 text_offset=0 "
"affinity=downstream annotated_text=<\n>",
- "TextPosition tree_id=0 anchor_id=7 text_offset=0 "
+ "TextPosition anchor_id=7 text_offset=0 "
"affinity=downstream annotated_text=<\n>"}},
TestParam{base::BindRepeating([](const TestPositionType& position) {
return position->CreatePreviousLineEndPosition(
@@ -3067,9 +3067,9 @@ INSTANTIATE_TEST_CASE_P(
}),
INLINE_BOX2_ID,
0 /* text_offset */,
- {"TextPosition tree_id=0 anchor_id=7 text_offset=0 "
+ {"TextPosition anchor_id=7 text_offset=0 "
"affinity=downstream annotated_text=<\n>",
- "TextPosition tree_id=0 anchor_id=7 text_offset=0 "
+ "TextPosition anchor_id=7 text_offset=0 "
"affinity=downstream annotated_text=<\n>"}}));
//
diff --git a/chromium/ui/accessibility/ax_position.h b/chromium/ui/accessibility/ax_position.h
index 0f3e6296a32..4bd039c96a9 100644
--- a/chromium/ui/accessibility/ax_position.h
+++ b/chromium/ui/accessibility/ax_position.h
@@ -152,8 +152,7 @@ class AXPosition {
} else {
str_text_offset = base::IntToString(text_offset_);
}
- str = "TextPosition tree_id=" + tree_id_.ToString() +
- " anchor_id=" + base::IntToString(anchor_id_) +
+ str = "TextPosition anchor_id=" + base::IntToString(anchor_id_) +
" text_offset=" + str_text_offset + " affinity=" +
ui::ToString(static_cast<ax::mojom::TextAffinity>(affinity_));
break;
diff --git a/chromium/ui/accessibility/ax_role_properties.cc b/chromium/ui/accessibility/ax_role_properties.cc
index 0c851bb60d4..a20ac839c62 100644
--- a/chromium/ui/accessibility/ax_role_properties.cc
+++ b/chromium/ui/accessibility/ax_role_properties.cc
@@ -160,6 +160,26 @@ bool IsImage(const ax::mojom::Role role) {
}
}
+bool IsItemLike(const ax::mojom::Role role) {
+ switch (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::kMenuListOption:
+ case ax::mojom::Role::kRadioButton:
+ case ax::mojom::Role::kDescriptionListTerm:
+ case ax::mojom::Role::kTerm:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool IsLink(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kDocBackLink:
@@ -230,6 +250,7 @@ bool IsMenuRelated(const ax::mojom::Role role) {
bool IsRowContainer(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kGrid:
+ case ax::mojom::Role::kListGrid:
case ax::mojom::Role::kTable:
case ax::mojom::Role::kTree:
case ax::mojom::Role::kTreeGrid:
@@ -241,6 +262,25 @@ bool IsRowContainer(const ax::mojom::Role role) {
}
}
+bool IsSetLike(const ax::mojom::Role role) {
+ switch (role) {
+ case ax::mojom::Role::kFeed:
+ case ax::mojom::Role::kList:
+ case ax::mojom::Role::kGroup:
+ case ax::mojom::Role::kMenu:
+ case ax::mojom::Role::kMenuBar:
+ case ax::mojom::Role::kTabList:
+ case ax::mojom::Role::kTree:
+ case ax::mojom::Role::kListBox:
+ case ax::mojom::Role::kMenuListPopup:
+ case ax::mojom::Role::kRadioGroup:
+ case ax::mojom::Role::kDescriptionList:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool IsTableHeader(ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kColumnHeader:
@@ -254,6 +294,7 @@ bool IsTableHeader(ax::mojom::Role role) {
bool IsTableLike(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kGrid:
+ case ax::mojom::Role::kListGrid:
case ax::mojom::Role::kTable:
case ax::mojom::Role::kTreeGrid:
return true;
diff --git a/chromium/ui/accessibility/ax_role_properties.h b/chromium/ui/accessibility/ax_role_properties.h
index c6a80263e06..d9a1e73baf7 100644
--- a/chromium/ui/accessibility/ax_role_properties.h
+++ b/chromium/ui/accessibility/ax_role_properties.h
@@ -41,6 +41,10 @@ AX_EXPORT bool IsHeadingOrTableHeader(const 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 the provided role is item-like, specifically if it can hold
+// pos_in_set and set_size values.
+AX_EXPORT bool IsItemLike(const ax::mojom::Role role);
+
// Returns true if the provided role belongs to a link.
AX_EXPORT bool IsLink(const ax::mojom::Role role);
@@ -61,6 +65,10 @@ AX_EXPORT bool IsMenuRelated(const ax::mojom::Role role);
// table or grid row.
AX_EXPORT bool IsRowContainer(const ax::mojom::Role role);
+// Returns true if the provided role is ordered-set like, specifically if it
+// can hold set_size values.
+AX_EXPORT bool IsSetLike(const ax::mojom::Role role);
+
// Returns true if the provided role belongs to a table header.
AX_EXPORT bool IsTableHeader(ax::mojom::Role role);
diff --git a/chromium/ui/accessibility/ax_table_info.cc b/chromium/ui/accessibility/ax_table_info.cc
index b3f79cc65ee..aa559a2021c 100644
--- a/chromium/ui/accessibility/ax_table_info.cc
+++ b/chromium/ui/accessibility/ax_table_info.cc
@@ -7,6 +7,7 @@
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_observer.h"
#include "ui/gfx/geometry/rect_f.h"
using ax::mojom::IntAttribute;
@@ -151,14 +152,22 @@ void AXTableInfo::BuildCellDataVectorFromRowAndCellNodes(
// 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;
+ int32_t previous_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;
+
+ // Make sure the row index is always at least as high as the one reported by
+ // Blink.
+ row_id_to_index[row_node->id()] =
+ std::max(previous_row_index + 1,
+ row_node->GetIntAttribute(IntAttribute::kTableRowIndex));
+ int32_t* current_row_index = &row_id_to_index[row_node->id()];
+
for (AXNode* cell : cell_nodes_in_this_row) {
// Fill in basic info in CellData.
CellData cell_data;
@@ -193,10 +202,13 @@ void AXTableInfo::BuildCellDataVectorFromRowAndCellNodes(
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;
+ // incrementing. The rest of the cells in this row are forced to have
+ // the same row index.
+ if (cell_data.row_index > *current_row_index) {
+ *current_row_index = cell_data.row_index;
+ } else {
+ cell_data.row_index = *current_row_index;
+ }
// The starting ARIA row and column index might be specified in
// the row node, we should check there.
@@ -214,7 +226,7 @@ void AXTableInfo::BuildCellDataVectorFromRowAndCellNodes(
} else {
// Don't allow the row index to change after the beginning
// of a row.
- cell_data.row_index = current_row_index;
+ cell_data.row_index = *current_row_index;
cell_data.aria_row_index = current_aria_row_index;
}
@@ -243,11 +255,11 @@ void AXTableInfo::BuildCellDataVectorFromRowAndCellNodes(
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++;
+ // At the end of each row, increment |current_aria_row_index| to reflect the
+ // next available index after this row. The next row index must be at least
+ // this large. Also update |previous_row_index|.
current_aria_row_index++;
+ previous_row_index = *current_row_index;
}
}
@@ -348,8 +360,8 @@ AXNode* AXTableInfo::CreateExtraMacColumnNode(int col_index) {
data.id = id;
data.role = ax::mojom::Role::kColumn;
node->SetData(data);
- if (tree_->delegate())
- tree_->delegate()->OnNodeCreated(tree_, node);
+ for (AXTreeObserver& observer : tree_->observers())
+ observer.OnNodeCreated(tree_, node);
return node;
}
@@ -361,8 +373,8 @@ AXNode* AXTableInfo::CreateExtraMacTableHeaderNode() {
data.id = id;
data.role = ax::mojom::Role::kTableHeaderContainer;
node->SetData(data);
- if (tree_->delegate())
- tree_->delegate()->OnNodeCreated(tree_, node);
+ for (AXTreeObserver& observer : tree_->observers())
+ observer.OnNodeCreated(tree_, node);
return node;
}
@@ -397,8 +409,8 @@ void AXTableInfo::UpdateExtraMacColumnNodeAttributes(int col_index) {
void AXTableInfo::ClearExtraMacNodes() {
for (size_t i = 0; i < extra_mac_nodes.size(); i++) {
- if (tree_->delegate())
- tree_->delegate()->OnNodeWillBeDeleted(tree_, extra_mac_nodes[i]);
+ for (AXTreeObserver& observer : tree_->observers())
+ observer.OnNodeWillBeDeleted(tree_, extra_mac_nodes[i]);
delete extra_mac_nodes[i];
}
}
diff --git a/chromium/ui/accessibility/ax_table_info.h b/chromium/ui/accessibility/ax_table_info.h
index 39c912c680c..030f8e37d9e 100644
--- a/chromium/ui/accessibility/ax_table_info.h
+++ b/chromium/ui/accessibility/ax_table_info.h
@@ -6,9 +6,9 @@
#define UI_ACCESSIBILITY_AX_TABLE_INFO_H_
#include <set>
+#include <unordered_map>
#include <vector>
-#include "base/containers/hash_tables.h"
#include "ui/accessibility/ax_export.h"
namespace ui {
@@ -80,7 +80,10 @@ class AX_EXPORT AXTableInfo {
std::vector<AXNode*> extra_mac_nodes;
// 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;
+ std::unordered_map<int32_t, int32_t> cell_id_to_index;
+
+ // Map from each row's node ID to its row index.
+ std::unordered_map<int32_t, int32_t> row_id_to_index;
// The ARIA row count and column count, if any ARIA table or grid
// attributes are used in the table at all.
diff --git a/chromium/ui/accessibility/ax_tree.cc b/chromium/ui/accessibility/ax_tree.cc
index 1b5932fbc80..a0b8c3cac32 100644
--- a/chromium/ui/accessibility/ax_tree.cc
+++ b/chromium/ui/accessibility/ax_tree.cc
@@ -13,7 +13,9 @@
#include "base/strings/stringprintf.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/ax_table_info.h"
+#include "ui/accessibility/ax_tree_observer.h"
#include "ui/gfx/transform.h"
namespace ui {
@@ -93,39 +95,50 @@ void CallIfAttributeValuesChanged(const std::vector<std::pair<K, V>>& pairs1,
struct AXTreeUpdateState {
AXTreeUpdateState() : new_root(nullptr) {}
// Returns whether this update changes |node|.
- bool HasChangedNode(const AXNode* node) {
+ bool IsChangedNode(const AXNode* node) {
return changed_node_ids.find(node->id()) != changed_node_ids.end();
}
// Returns whether this update removes |node|.
- bool HasRemovedNode(const AXNode* node) {
+ bool IsRemovedNode(const AXNode* node) {
return removed_node_ids.find(node->id()) != removed_node_ids.end();
}
+ // Returns whether this update creates |node|.
+ bool IsNewNode(const AXNode* node) {
+ return new_nodes.find(node) != new_nodes.end();
+ }
+
+ // Returns whether this update reparents |node|.
+ bool IsReparentedNode(const AXNode* node) {
+ return IsNewNode(node) && IsRemovedNode(node);
+ }
+
// During an update, this keeps track of all nodes that have been
// implicitly referenced as part of this update, but haven't been
// updated yet. It's an error if there are any pending nodes at the
// end of Unserialize.
- std::set<AXNode*> pending_nodes;
+ std::set<const AXNode*> pending_nodes;
// This is similar to above, but we store node ids here because this list gets
// generated before any nodes get created or re-used. Its purpose is to allow
// us to know what nodes will be updated so we can make more intelligent
- // decisions about when to notify delegates of removals or reparenting.
+ // decisions about when to notify observers of removals or reparenting.
std::set<int> changed_node_ids;
// Keeps track of new nodes created during this update.
- std::set<AXNode*> new_nodes;
+ std::set<const AXNode*> new_nodes;
// The new root in this update, if any.
AXNode* new_root;
// Keeps track of any nodes removed. Used to identify re-parented nodes.
std::set<int> removed_node_ids;
-};
-AXTreeDelegate::AXTreeDelegate() = default;
-AXTreeDelegate::~AXTreeDelegate() = default;
+ // Maps between a node id and its data. We need to keep this around because
+ // the reparented nodes in this update were actually deleted.
+ std::map<int32_t, AXNodeData> reparented_node_id_to_data;
+};
AXTree::AXTree() {
AXNodeData root;
@@ -149,8 +162,16 @@ AXTree::~AXTree() {
table_info_map_.clear();
}
-void AXTree::SetDelegate(AXTreeDelegate* delegate) {
- delegate_ = delegate;
+void AXTree::AddObserver(AXTreeObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+bool AXTree::HasObserver(AXTreeObserver* observer) {
+ return observers_.HasObserver(observer);
+}
+
+void AXTree::RemoveObserver(const AXTreeObserver* observer) {
+ observers_.RemoveObserver(observer);
}
AXNode* AXTree::GetFromId(int32_t id) const {
@@ -164,8 +185,8 @@ void AXTree::UpdateData(const AXTreeData& new_data) {
AXTreeData old_data = data_;
data_ = new_data;
- if (delegate_)
- delegate_->OnTreeDataChanged(this, old_data, new_data);
+ for (AXTreeObserver& observer : observers_)
+ observer.OnTreeDataChanged(this, old_data, new_data);
}
gfx::RectF AXTree::RelativeToTreeBounds(const AXNode* node,
@@ -424,50 +445,51 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
}
}
- if (delegate_) {
- std::set<AXNode*>& new_nodes = update_state.new_nodes;
- std::vector<AXTreeDelegate::Change> changes;
- changes.reserve(update.nodes.size());
- for (size_t i = 0; i < update.nodes.size(); ++i) {
- AXNode* node = GetFromId(update.nodes[i].id);
- if (!node)
- continue;
-
- bool is_new_node = new_nodes.find(node) != new_nodes.end();
- bool is_reparented_node =
- is_new_node && update_state.HasRemovedNode(node);
-
- AXTreeDelegate::ChangeType change = AXTreeDelegate::NODE_CHANGED;
- if (is_new_node) {
- if (is_reparented_node) {
- // A reparented subtree is any new node whose parent either doesn't
- // exist, or whose parent is not new.
- // Note that we also need to check for the special case when we update
- // the root without replacing it.
- bool is_subtree = !node->parent() ||
- new_nodes.find(node->parent()) == new_nodes.end() ||
- (node->parent() == root_ && root_updated);
- change = is_subtree ? AXTreeDelegate::SUBTREE_REPARENTED
- : AXTreeDelegate::NODE_REPARENTED;
- } else {
- // A new subtree is any new node whose parent is either not new, or
- // whose parent happens to be new only because it has been reparented.
- // Note that we also need to check for the special case when we update
- // the root without replacing it.
- bool is_subtree = !node->parent() ||
- new_nodes.find(node->parent()) == new_nodes.end() ||
- update_state.HasRemovedNode(node->parent()) ||
- (node->parent() == root_ && root_updated);
- change = is_subtree ? AXTreeDelegate::SUBTREE_CREATED
- : AXTreeDelegate::NODE_CREATED;
- }
+ std::set<const AXNode*>& new_nodes = update_state.new_nodes;
+ std::vector<AXTreeObserver::Change> changes;
+ changes.reserve(update.nodes.size());
+ for (size_t i = 0; i < update.nodes.size(); ++i) {
+ AXNode* node = GetFromId(update.nodes[i].id);
+ if (!node)
+ continue;
+
+ bool is_new_node = update_state.IsNewNode(node);
+ bool is_reparented_node = update_state.IsReparentedNode(node);
+
+ AXTreeObserver::ChangeType change = AXTreeObserver::NODE_CHANGED;
+ if (is_new_node) {
+ if (is_reparented_node) {
+ // A reparented subtree is any new node whose parent either doesn't
+ // exist, or whose parent is not new.
+ // Note that we also need to check for the special case when we update
+ // the root without replacing it.
+ bool is_subtree = !node->parent() ||
+ new_nodes.find(node->parent()) == new_nodes.end() ||
+ (node->parent() == root_ && root_updated);
+ change = is_subtree ? AXTreeObserver::SUBTREE_REPARENTED
+ : AXTreeObserver::NODE_REPARENTED;
+ } else {
+ // A new subtree is any new node whose parent is either not new, or
+ // whose parent happens to be new only because it has been reparented.
+ // Note that we also need to check for the special case when we update
+ // the root without replacing it.
+ bool is_subtree = !node->parent() ||
+ new_nodes.find(node->parent()) == new_nodes.end() ||
+ update_state.IsRemovedNode(node->parent()) ||
+ (node->parent() == root_ && root_updated);
+ change = is_subtree ? AXTreeObserver::SUBTREE_CREATED
+ : AXTreeObserver::NODE_CREATED;
}
- changes.push_back(AXTreeDelegate::Change(node, change));
}
- delegate_->OnAtomicUpdateFinished(
- this, root_->id() != old_root_id, changes);
+ changes.push_back(AXTreeObserver::Change(node, change));
+ }
+ for (AXTreeObserver& observer : observers_) {
+ observer.OnAtomicUpdateFinished(this, root_->id() != old_root_id, changes);
}
+ // Clear list_info_map_
+ ordered_set_info_map_.clear();
+
return true;
}
@@ -495,8 +517,8 @@ AXTableInfo* AXTree::GetTableInfo(const AXNode* const_table_node) const {
table_info_map_.erase(table_node->id());
}
// See note about const_cast, above.
- if (delegate_)
- delegate_->OnNodeChanged(tree, table_node);
+ for (AXTreeObserver& observer : observers_)
+ observer.OnNodeChanged(tree, table_node);
}
return table_info;
}
@@ -506,8 +528,8 @@ AXTableInfo* AXTree::GetTableInfo(const AXNode* const_table_node) const {
return nullptr;
table_info_map_[table_node->id()] = table_info;
- if (delegate_)
- delegate_->OnNodeChanged(tree, table_node);
+ for (AXTreeObserver& observer : observers_)
+ observer.OnNodeChanged(tree, table_node);
return table_info;
}
@@ -522,12 +544,12 @@ AXNode* AXTree::CreateNode(AXNode* parent,
AXTreeUpdateState* update_state) {
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) &&
- !update_state->HasRemovedNode(new_node))
- delegate_->OnNodeCreated(this, new_node);
+ for (AXTreeObserver& observer : observers_) {
+ if (update_state->IsChangedNode(new_node) &&
+ !update_state->IsRemovedNode(new_node))
+ observer.OnNodeCreated(this, new_node);
else
- delegate_->OnNodeReparented(this, new_node);
+ observer.OnNodeReparented(this, new_node);
}
return new_node;
}
@@ -549,8 +571,14 @@ bool AXTree::UpdateNode(const AXNodeData& src,
// TODO(accessibility): CallNodeChangeCallbacks should not pass |node|,
// since the tree and the node data are not yet in a consistent
// state. Possibly only pass id.
- if (update_state->new_nodes.find(node) == update_state->new_nodes.end())
- CallNodeChangeCallbacks(node, src);
+ if (!update_state->IsNewNode(node) ||
+ update_state->IsReparentedNode(node)) {
+ auto it = update_state->reparented_node_id_to_data.find(node->id());
+ if (it != update_state->reparented_node_id_to_data.end())
+ CallNodeChangeCallbacks(node, it->second, src);
+ else
+ CallNodeChangeCallbacks(node, node->data(), src);
+ }
UpdateReverseRelations(node, src);
node->SetData(src);
} else {
@@ -567,8 +595,8 @@ bool AXTree::UpdateNode(const AXNodeData& src,
node->SetData(src);
}
- if (delegate_)
- delegate_->OnNodeChanged(this, node);
+ for (AXTreeObserver& observer : observers_)
+ observer.OnNodeChanged(this, node);
// First, delete nodes that used to be children of this node but aren't
// anymore.
@@ -613,30 +641,35 @@ bool AXTree::UpdateNode(const AXNodeData& src,
return success;
}
-void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) {
- if (!delegate_)
- return;
+void AXTree::CallNodeChangeCallbacks(AXNode* node,
+ const AXNodeData& old_data,
+ const AXNodeData& new_data) {
+ for (AXTreeObserver& observer : observers_)
+ observer.OnNodeDataWillChange(this, old_data, new_data);
- const AXNodeData& old_data = node->data();
- delegate_->OnNodeDataWillChange(this, old_data, new_data);
-
- if (old_data.role != new_data.role)
- delegate_->OnRoleChanged(this, node, old_data.role, new_data.role);
+ if (old_data.role != new_data.role) {
+ for (AXTreeObserver& observer : observers_)
+ observer.OnRoleChanged(this, node, old_data.role, new_data.role);
+ }
if (old_data.state != new_data.state) {
for (int32_t i = static_cast<int32_t>(ax::mojom::State::kNone) + 1;
i <= static_cast<int32_t>(ax::mojom::State::kMaxValue); ++i) {
ax::mojom::State state = static_cast<ax::mojom::State>(i);
- if (old_data.HasState(state) != new_data.HasState(state))
- delegate_->OnStateChanged(this, node, state, new_data.HasState(state));
+ if (old_data.HasState(state) != new_data.HasState(state)) {
+ for (AXTreeObserver& observer : observers_)
+ observer.OnStateChanged(this, node, state, new_data.HasState(state));
+ }
}
}
auto string_callback = [this, node](ax::mojom::StringAttribute attr,
const std::string& old_string,
const std::string& new_string) {
- delegate_->OnStringAttributeChanged(this, node, attr, old_string,
+ for (AXTreeObserver& observer : observers_) {
+ observer.OnStringAttributeChanged(this, node, attr, old_string,
new_string);
+ }
};
CallIfAttributeValuesChanged(old_data.string_attributes,
new_data.string_attributes, std::string(),
@@ -645,7 +678,8 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) {
auto bool_callback = [this, node](ax::mojom::BoolAttribute attr,
const bool& old_bool,
const bool& new_bool) {
- delegate_->OnBoolAttributeChanged(this, node, attr, new_bool);
+ for (AXTreeObserver& observer : observers_)
+ observer.OnBoolAttributeChanged(this, node, attr, new_bool);
};
CallIfAttributeValuesChanged(old_data.bool_attributes,
new_data.bool_attributes, false, bool_callback);
@@ -653,14 +687,16 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) {
auto float_callback = [this, node](ax::mojom::FloatAttribute attr,
const float& old_float,
const float& new_float) {
- delegate_->OnFloatAttributeChanged(this, node, attr, old_float, new_float);
+ for (AXTreeObserver& observer : observers_)
+ observer.OnFloatAttributeChanged(this, node, attr, old_float, new_float);
};
CallIfAttributeValuesChanged(old_data.float_attributes,
new_data.float_attributes, 0.0f, float_callback);
auto int_callback = [this, node](ax::mojom::IntAttribute attr,
const int& old_int, const int& new_int) {
- delegate_->OnIntAttributeChanged(this, node, attr, old_int, new_int);
+ for (AXTreeObserver& observer : observers_)
+ observer.OnIntAttributeChanged(this, node, attr, old_int, new_int);
};
CallIfAttributeValuesChanged(old_data.int_attributes, new_data.int_attributes,
0, int_callback);
@@ -669,7 +705,8 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) {
ax::mojom::IntListAttribute attr,
const std::vector<int32_t>& old_intlist,
const std::vector<int32_t>& new_intlist) {
- delegate_->OnIntListAttributeChanged(this, node, attr, old_intlist,
+ for (AXTreeObserver& observer : observers_)
+ observer.OnIntListAttributeChanged(this, node, attr, old_intlist,
new_intlist);
};
CallIfAttributeValuesChanged(old_data.intlist_attributes,
@@ -680,7 +717,8 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) {
[this, node](ax::mojom::StringListAttribute attr,
const std::vector<std::string>& old_stringlist,
const std::vector<std::string>& new_stringlist) {
- delegate_->OnStringListAttributeChanged(this, node, attr,
+ for (AXTreeObserver& observer : observers_)
+ observer.OnStringListAttributeChanged(this, node, attr,
old_stringlist, new_stringlist);
};
CallIfAttributeValuesChanged(old_data.stringlist_attributes,
@@ -765,11 +803,11 @@ void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) {
void AXTree::DestroySubtree(AXNode* node,
AXTreeUpdateState* update_state) {
DCHECK(update_state);
- if (delegate_) {
- if (!update_state->HasChangedNode(node))
- delegate_->OnSubtreeWillBeDeleted(this, node);
+ for (AXTreeObserver& observer : observers_) {
+ if (!update_state->IsChangedNode(node))
+ observer.OnSubtreeWillBeDeleted(this, node);
else
- delegate_->OnSubtreeWillBeReparented(this, node);
+ observer.OnSubtreeWillBeReparented(this, node);
}
DestroyNodeAndSubtree(node, update_state);
}
@@ -788,11 +826,11 @@ void AXTree::DestroyNodeAndSubtree(AXNode* node,
table_info_map_.erase(node->id());
}
- if (delegate_) {
- if (!update_state || !update_state->HasChangedNode(node))
- delegate_->OnNodeWillBeDeleted(this, node);
+ for (AXTreeObserver& observer : observers_) {
+ if (!update_state || !update_state->IsChangedNode(node))
+ observer.OnNodeWillBeDeleted(this, node);
else
- delegate_->OnNodeWillBeReparented(this, node);
+ observer.OnNodeWillBeReparented(this, node);
}
id_map_.erase(node->id());
for (int i = 0; i < node->child_count(); ++i)
@@ -801,6 +839,11 @@ void AXTree::DestroyNodeAndSubtree(AXNode* node,
update_state->pending_nodes.erase(node);
update_state->removed_node_ids.insert(node->id());
}
+
+ if (update_state && update_state->IsChangedNode(node)) {
+ update_state->reparented_node_id_to_data.insert(
+ std::make_pair(node->id(), node->TakeData()));
+ }
node->Destroy();
}
@@ -878,4 +921,147 @@ int32_t AXTree::GetNextNegativeInternalNodeId() {
return return_value;
}
+// Populates items vector with all items within ordered_set.
+// Will only add items whose roles match the role of the
+// ordered_set.
+void AXTree::PopulateOrderedSetItems(const AXNode* ordered_set,
+ const AXNode* local_parent,
+ std::vector<const AXNode*>& items,
+ bool node_is_radio_button) const {
+ // Stop searching current path if roles of local_parent and ordered set match.
+ // Don't compare the container to itself.
+ if (!(ordered_set == local_parent)) {
+ if (local_parent->data().role == ordered_set->data().role)
+ return;
+ }
+
+ for (int i = 0; i < local_parent->child_count(); ++i) {
+ const AXNode* child = local_parent->GetUnignoredChildAtIndex(i);
+
+ // If role of node is kRadioButton, only add other kRadioButtons.
+ if (node_is_radio_button &&
+ child->data().role == ax::mojom::Role::kRadioButton)
+ items.push_back(child);
+
+ // Add child to items if role matches with ordered set's role. If role of
+ // node is kRadioButton, don't add items of other roles, even if item role
+ // matches ordered set role.
+ if (!node_is_radio_button && child->SetRoleMatchesItemRole(ordered_set))
+ 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) {
+ PopulateOrderedSetItems(ordered_set, child, items, node_is_radio_button);
+ }
+ }
+}
+
+// Given an ordered_set, compute pos_in_set and set_size for all of its items
+// and store values in cache.
+// Ordered_set should never be nullptr.
+void AXTree::ComputeSetSizePosInSetAndCache(const AXNode& node,
+ const AXNode* ordered_set) {
+ DCHECK(ordered_set);
+ std::vector<const AXNode*> items;
+
+ // True if the role of AXNode GetPosInSet() was called on is a kRadioButton.
+ bool node_is_radio_button =
+ (node.data().role == ax::mojom::Role::kRadioButton);
+
+ // Find all items within ordered_set and add to vector.
+ PopulateOrderedSetItems(ordered_set, ordered_set, items,
+ node_is_radio_button);
+
+ // Keep track of the number of elements ordered_set has.
+ int32_t num_elements = 0;
+
+ // Necessary for calculating set_size.
+ int32_t largest_assigned_set_size = 0;
+
+ // Compute pos_in_set_values.
+ for (size_t i = 0; i < items.size(); ++i) {
+ const AXNode* item = items[i];
+ ordered_set_info_map_[item->id()] = OrderedSetInfo();
+ int32_t pos_in_set_value = 0;
+
+ pos_in_set_value = num_elements + 1;
+
+ // Check if item has a valid kPosInSet assignment, which takes precedence
+ // over previous assignment. Invalid assignments are decreasing or
+ // duplicates, and should be ignored.
+ pos_in_set_value =
+ std::max(pos_in_set_value,
+ item->GetIntAttribute(ax::mojom::IntAttribute::kPosInSet));
+
+ // Assign pos_in_set and update role counts.
+ ordered_set_info_map_[item->id()].pos_in_set = pos_in_set_value;
+ num_elements = pos_in_set_value;
+
+ // Check if kSetSize is assigned and update if it's the largest assigned
+ // kSetSize.
+ if (item->HasIntAttribute(ax::mojom::IntAttribute::kSetSize))
+ largest_assigned_set_size =
+ std::max(largest_assigned_set_size,
+ item->GetIntAttribute(ax::mojom::IntAttribute::kSetSize));
+ }
+
+ // Compute set_size value.
+ // The SetSize of an ordered set (and all of its items) is the maximum of the
+ // following candidate values:
+ // 1. The number of elements in the ordered set.
+ // 2. The Largest assigned SetSize in the ordered set.
+ // 3. The SetSize assigned within the ordered set.
+
+ // Set to 0 if ordered_set has no kSetSize attribute.
+ int32_t ordered_set_candidate =
+ ordered_set->GetIntAttribute(ax::mojom::IntAttribute::kSetSize);
+
+ int32_t set_size_value = std::max(
+ std::max(num_elements, largest_assigned_set_size), ordered_set_candidate);
+
+ // If ordered_set is not in the cache, assign it a new set_size.
+ if (ordered_set_info_map_.find(ordered_set->id()) ==
+ ordered_set_info_map_.end())
+ ordered_set_info_map_[ordered_set->id()] = OrderedSetInfo();
+
+ // Assign set_size to ordered_set.
+ // Must meet one of two conditions:
+ // 1. Node role matches ordered set role.
+ // 2. The node that calculations were called on is the ordered_set.
+ if (node.SetRoleMatchesItemRole(ordered_set) || ordered_set == &node)
+ ordered_set_info_map_[ordered_set->id()].set_size = set_size_value;
+
+ // Assign set_size to items.
+ for (size_t j = 0; j < items.size(); ++j) {
+ const AXNode* item = items[j];
+ ordered_set_info_map_[item->id()].set_size = set_size_value;
+ }
+}
+
+// Returns the pos_in_set of item. Looks in ordered_set_info_map_ for cached
+// value. Calculates pos_in_set and set_size for item (and all other items in
+// the same ordered set) if no value is present in the cache.
+// This function is guaranteed to be only called on nodes that can hold
+// pos_in_set values, minimizing the size of the cache.
+int32_t AXTree::GetPosInSet(const AXNode& node, const AXNode* ordered_set) {
+ // If item's id is not in the cache, compute it.
+ if (ordered_set_info_map_.find(node.id()) == ordered_set_info_map_.end())
+ ComputeSetSizePosInSetAndCache(node, ordered_set);
+ return ordered_set_info_map_[node.id()].pos_in_set;
+}
+
+// Returns the set_size of node. node could be an ordered set or an item.
+// Looks in ordered_set_info_map_ for cached value. Calculates pos_inset_set
+// and set_size for all nodes in same ordered set if no value is present in the
+// cache.
+// This function is guaranteed to be only called on nodes that can hold
+// set_size values, minimizing the size of the cache.
+int32_t AXTree::GetSetSize(const AXNode& node, const AXNode* ordered_set) {
+ // If node's id is not in the cache, compute it.
+ if (ordered_set_info_map_.find(node.id()) == ordered_set_info_map_.end())
+ ComputeSetSizePosInSetAndCache(node, ordered_set);
+ return ordered_set_info_map_[node.id()].set_size;
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree.h b/chromium/ui/accessibility/ax_tree.h
index fb8f2b74d68..66be06f7937 100644
--- a/chromium/ui/accessibility/ax_tree.h
+++ b/chromium/ui/accessibility/ax_tree.h
@@ -8,8 +8,9 @@
#include <stdint.h>
#include <set>
+#include <unordered_map>
-#include "base/containers/hash_tables.h"
+#include "base/observer_list.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h"
@@ -20,138 +21,9 @@ namespace ui {
class AXTableInfo;
class AXTree;
+class AXTreeObserver;
struct AXTreeUpdateState;
-// Used when you want to be notified when changes happen to the tree.
-//
-// Some of the notifications are called in the middle of an update operation.
-// Be careful, as the tree may be in an inconsistent state at this time;
-// don't walk the parents and children at this time:
-// OnNodeWillBeDeleted
-// OnSubtreeWillBeDeleted
-// OnNodeWillBeReparented
-// OnSubtreeWillBeReparented
-// OnNodeCreated
-// OnNodeReparented
-// OnNodeChanged
-//
-// In addition, one additional notification is fired at the end of an
-// atomic update, and it provides a vector of nodes that were added or
-// changed, for final postprocessing:
-// OnAtomicUpdateFinished
-//
-class AX_EXPORT AXTreeDelegate {
- public:
- AXTreeDelegate();
- virtual ~AXTreeDelegate();
-
- // Called before a node's data gets updated.
- virtual void OnNodeDataWillChange(AXTree* tree,
- const AXNodeData& old_node_data,
- const AXNodeData& new_node_data) = 0;
-
- // Individual callbacks for every attribute of AXNodeData that can change.
- virtual void OnRoleChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::Role old_role,
- ax::mojom::Role new_role) {}
- virtual void OnStateChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::State state,
- bool new_value) {}
- virtual void OnStringAttributeChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::StringAttribute attr,
- const std::string& old_value,
- const std::string& new_value) {}
- virtual void OnIntAttributeChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::IntAttribute attr,
- int32_t old_value,
- int32_t new_value) {}
- virtual void OnFloatAttributeChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::FloatAttribute attr,
- float old_value,
- float new_value) {}
- virtual void OnBoolAttributeChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::BoolAttribute attr,
- bool new_value) {}
- virtual void OnIntListAttributeChanged(
- AXTree* tree,
- AXNode* node,
- ax::mojom::IntListAttribute attr,
- const std::vector<int32_t>& old_value,
- const std::vector<int32_t>& new_value) {}
- virtual void OnStringListAttributeChanged(
- AXTree* tree,
- AXNode* node,
- ax::mojom::StringListAttribute attr,
- const std::vector<std::string>& old_value,
- const std::vector<std::string>& new_value) {}
-
- // Called when tree data changes.
- virtual void OnTreeDataChanged(AXTree* tree,
- const ui::AXTreeData& old_data,
- const ui::AXTreeData& new_data) = 0;
- // Called just before a node is deleted. Its id and data will be valid,
- // but its links to parents and children are invalid. This is called
- // in the middle of an update, the tree may be in an invalid state!
- virtual void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) = 0;
-
- // Same as OnNodeWillBeDeleted, but only called once for an entire subtree.
- // This is called in the middle of an update, the tree may be in an
- // invalid state!
- virtual void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) = 0;
-
- // Called just before a node is deleted for reparenting. See
- // |OnNodeWillBeDeleted| for additional information.
- virtual void OnNodeWillBeReparented(AXTree* tree, AXNode* node) = 0;
-
- // Called just before a subtree is deleted for reparenting. See
- // |OnSubtreeWillBeDeleted| for additional information.
- virtual void OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) = 0;
-
- // Called immediately after a new node is created. The tree may be in
- // the middle of an update, don't walk the parents and children now.
- virtual void OnNodeCreated(AXTree* tree, AXNode* node) = 0;
-
- // Called immediately after a node is reparented. The tree may be in the
- // middle of an update, don't walk the parents and children now.
- virtual void OnNodeReparented(AXTree* tree, AXNode* node) = 0;
-
- // Called when a node changes its data or children. The tree may be in
- // the middle of an update, don't walk the parents and children now.
- virtual void OnNodeChanged(AXTree* tree, AXNode* node) = 0;
-
- enum ChangeType {
- NODE_CREATED,
- SUBTREE_CREATED,
- NODE_CHANGED,
- NODE_REPARENTED,
- SUBTREE_REPARENTED
- };
-
- struct Change {
- Change(AXNode* node, ChangeType type) {
- this->node = node;
- this->type = type;
- }
- AXNode* node;
- ChangeType type;
- };
-
- // Called at the end of the update operation. Every node that was added
- // or changed will be included in |changes|, along with an enum indicating
- // the type of change - either (1) a node was created, (2) a node was created
- // and it's the root of a new subtree, or (3) a node was changed. Finally,
- // a bool indicates if the root of the tree was changed or not.
- virtual void OnAtomicUpdateFinished(AXTree* tree,
- bool root_changed,
- const std::vector<Change>& changes) = 0;
-};
-
// AXTree is a live, managed tree of AXNode objects that can receive
// updates from another AXTreeSource via AXTreeUpdates, and it can be
// used as a source for sending updates to another client tree.
@@ -170,8 +42,11 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
explicit AXTree(const AXTreeUpdate& initial_state);
virtual ~AXTree();
- virtual void SetDelegate(AXTreeDelegate* delegate);
- AXTreeDelegate* delegate() const { return delegate_; }
+ void AddObserver(AXTreeObserver* observer);
+ bool HasObserver(AXTreeObserver* observer);
+ void RemoveObserver(const AXTreeObserver* observer);
+
+ base::ObserverList<AXTreeObserver>& observers() { return observers_; }
AXNode* root() const { return root_; }
@@ -257,6 +132,19 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// conflict with positive-numbered node IDs from tree sources.
int32_t GetNextNegativeInternalNodeId();
+ // Returns the pos_in_set of node. Looks in ordered_set_info_map_ for cached
+ // value. Calculates pos_in_set and set_size for node (and all other nodes in
+ // the same ordered set) if no value is present in the cache.
+ // This function is guaranteed to be only called on nodes that can hold
+ // pos_in_set values, minimizing the size of the cache.
+ int32_t GetPosInSet(const AXNode& node, const AXNode* ordered_set) override;
+ // Returns the set_size of node. Looks in ordered_set_info_map_ for cached
+ // value. Calculates pos_inset_set and set_size for node (and all other nodes
+ // in the same ordered set) if no value is present in the cache.
+ // This function is guaranteed to be only called on nodes that can hold
+ // set_size values, minimizing the size of the cache.
+ int32_t GetSetSize(const AXNode& node, const AXNode* ordered_set) override;
+
private:
friend class AXTableInfoTest;
@@ -282,7 +170,9 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
bool is_new_root,
AXTreeUpdateState* update_state);
- void CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data);
+ void CallNodeChangeCallbacks(AXNode* node,
+ const AXNodeData& old_data,
+ const AXNodeData& new_data);
void UpdateReverseRelations(AXNode* node, const AXNodeData& new_data);
@@ -313,9 +203,9 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
std::vector<AXNode*>* new_children,
AXTreeUpdateState* update_state);
- AXTreeDelegate* delegate_ = nullptr;
+ base::ObserverList<AXTreeObserver> observers_;
AXNode* root_ = nullptr;
- base::hash_map<int32_t, AXNode*> id_map_;
+ std::unordered_map<int32_t, AXNode*> id_map_;
std::string error_;
AXTreeData data_;
@@ -330,7 +220,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// Map from node ID to cached table info, if the given node is a table.
// Invalidated every time the tree is updated.
- mutable base::hash_map<int32_t, AXTableInfo*> table_info_map_;
+ mutable std::unordered_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;
@@ -340,6 +230,37 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// this code to be unit-tested on other platforms (for example, more
// code sanitizers run on Linux).
bool enable_extra_mac_nodes_ = false;
+
+ // Contains pos_in_set and set_size data for an AXNode.
+ struct OrderedSetInfo {
+ int32_t pos_in_set;
+ int32_t set_size;
+ OrderedSetInfo() : pos_in_set(0), set_size(0) {}
+ ~OrderedSetInfo() {}
+ };
+
+ // Populates items vector with all items within ordered_set.
+ // Will only add items whose roles match the role of the
+ // ordered_set.
+ void PopulateOrderedSetItems(const AXNode* ordered_set,
+ const AXNode* local_parent,
+ std::vector<const AXNode*>& items,
+ bool node_is_radio_button) const;
+
+ // Helper for GetPosInSet and GetSetSize. Computes the pos_in_set and set_size
+ // values of all items in ordered_set and caches those values.
+ void ComputeSetSizePosInSetAndCache(const AXNode& node,
+ const AXNode* ordered_set);
+
+ // Map from node ID to OrderedSetInfo.
+ // Item-like and ordered-set-like objects will map to populated OrderedSetInfo
+ // objects.
+ // All other objects will map to default-constructed OrderedSetInfo objects.
+ // Invalidated every time the tree is updated.
+ mutable std::unordered_map<int32_t, OrderedSetInfo> ordered_set_info_map_;
+
+ // AXTree owns pointers so copying is non-trivial.
+ DISALLOW_COPY_AND_ASSIGN(AXTree);
};
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_combiner_unittest.cc b/chromium/ui/accessibility/ax_tree_combiner_unittest.cc
index 5e8d1dc7825..e620a336a8e 100644
--- a/chromium/ui/accessibility/ax_tree_combiner_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_combiner_unittest.cc
@@ -8,9 +8,11 @@
namespace ui {
TEST(CombineAXTreesTest, RenumberOneTree) {
+ AXTreeID tree_id_1 = AXTreeID::CreateNewAXTreeID();
+
AXTreeUpdate tree;
tree.has_tree_data = true;
- tree.tree_data.tree_id = ui::AXTreeID::FromString("1");
+ tree.tree_data.tree_id = tree_id_1;
tree.root_id = 2;
tree.nodes.resize(3);
tree.nodes[0].id = 2;
@@ -36,10 +38,13 @@ TEST(CombineAXTreesTest, RenumberOneTree) {
}
TEST(CombineAXTreesTest, EmbedChildTree) {
+ AXTreeID tree_id_1 = AXTreeID::CreateNewAXTreeID();
+ AXTreeID tree_id_2 = AXTreeID::CreateNewAXTreeID();
+
AXTreeUpdate parent_tree;
parent_tree.root_id = 1;
parent_tree.has_tree_data = true;
- parent_tree.tree_data.tree_id = ui::AXTreeID::FromString("1");
+ parent_tree.tree_data.tree_id = tree_id_1;
parent_tree.nodes.resize(3);
parent_tree.nodes[0].id = 1;
parent_tree.nodes[0].child_ids.push_back(2);
@@ -49,13 +54,13 @@ TEST(CombineAXTreesTest, EmbedChildTree) {
parent_tree.nodes[2].id = 3;
parent_tree.nodes[2].role = ax::mojom::Role::kIframe;
parent_tree.nodes[2].AddStringAttribute(
- ax::mojom::StringAttribute::kChildTreeId, "2");
+ ax::mojom::StringAttribute::kChildTreeId, tree_id_2.ToString());
AXTreeUpdate child_tree;
child_tree.root_id = 1;
child_tree.has_tree_data = true;
- child_tree.tree_data.parent_tree_id = ui::AXTreeID::FromString("1");
- child_tree.tree_data.tree_id = ui::AXTreeID::FromString("2");
+ child_tree.tree_data.parent_tree_id = tree_id_1;
+ child_tree.tree_data.tree_id = tree_id_2;
child_tree.nodes.resize(3);
child_tree.nodes[0].id = 1;
child_tree.nodes[0].child_ids.push_back(2);
@@ -92,12 +97,14 @@ TEST(CombineAXTreesTest, EmbedChildTree) {
}
TEST(CombineAXTreesTest, MapAllIdAttributes) {
+ AXTreeID tree_id_1 = AXTreeID::CreateNewAXTreeID();
+
// This is a nonsensical accessibility tree, the goal is to make sure
// that all attributes that reference IDs of other nodes are remapped.
AXTreeUpdate tree;
tree.has_tree_data = true;
- tree.tree_data.tree_id = ui::AXTreeID::FromString("1");
+ tree.tree_data.tree_id = tree_id_1;
tree.root_id = 11;
tree.nodes.resize(2);
tree.nodes[0].id = 11;
@@ -155,10 +162,13 @@ TEST(CombineAXTreesTest, MapAllIdAttributes) {
}
TEST(CombineAXTreesTest, FocusedTree) {
+ AXTreeID tree_id_1 = AXTreeID::CreateNewAXTreeID();
+ AXTreeID tree_id_2 = AXTreeID::CreateNewAXTreeID();
+
AXTreeUpdate parent_tree;
parent_tree.has_tree_data = true;
- parent_tree.tree_data.tree_id = ui::AXTreeID::FromString("1");
- parent_tree.tree_data.focused_tree_id = ui::AXTreeID::FromString("2");
+ parent_tree.tree_data.tree_id = tree_id_1;
+ parent_tree.tree_data.focused_tree_id = tree_id_2;
parent_tree.tree_data.focus_id = 2;
parent_tree.root_id = 1;
parent_tree.nodes.resize(3);
@@ -170,12 +180,12 @@ TEST(CombineAXTreesTest, FocusedTree) {
parent_tree.nodes[2].id = 3;
parent_tree.nodes[2].role = ax::mojom::Role::kIframe;
parent_tree.nodes[2].AddStringAttribute(
- ax::mojom::StringAttribute::kChildTreeId, "2");
+ ax::mojom::StringAttribute::kChildTreeId, tree_id_2.ToString());
AXTreeUpdate child_tree;
child_tree.has_tree_data = true;
- child_tree.tree_data.parent_tree_id = ui::AXTreeID::FromString("1");
- child_tree.tree_data.tree_id = ui::AXTreeID::FromString("2");
+ child_tree.tree_data.parent_tree_id = tree_id_1;
+ child_tree.tree_data.tree_id = tree_id_2;
child_tree.tree_data.focus_id = 3;
child_tree.root_id = 1;
child_tree.nodes.resize(3);
diff --git a/chromium/ui/accessibility/ax_tree_data.cc b/chromium/ui/accessibility/ax_tree_data.cc
index ec452ba6d57..ee2a8e1368b 100644
--- a/chromium/ui/accessibility/ax_tree_data.cc
+++ b/chromium/ui/accessibility/ax_tree_data.cc
@@ -24,11 +24,11 @@ std::string AXTreeData::ToString() const {
std::string result;
if (tree_id != AXTreeIDUnknown())
- result += " tree_id=" + tree_id.ToString();
+ result += " tree_id=" + tree_id.ToString().substr(0, 8);
if (parent_tree_id != AXTreeIDUnknown())
- result += " parent_tree_id=" + parent_tree_id.ToString();
+ result += " parent_tree_id=" + parent_tree_id.ToString().substr(0, 8);
if (focused_tree_id != AXTreeIDUnknown())
- result += " focused_tree_id=" + focused_tree_id.ToString();
+ result += " focused_tree_id=" + focused_tree_id.ToString().substr(0, 8);
if (!doctype.empty())
result += " doctype=" + doctype;
diff --git a/chromium/ui/accessibility/ax_tree_fuzzer.cc b/chromium/ui/accessibility/ax_tree_fuzzer.cc
index 6f04976634d..f2ad7271fc2 100644
--- a/chromium/ui/accessibility/ax_tree_fuzzer.cc
+++ b/chromium/ui/accessibility/ax_tree_fuzzer.cc
@@ -3,27 +3,12 @@
// found in the LICENSE file.
#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_observer.h"
-class EmptyAXTreeDelegate : public ui::AXTreeDelegate {
+class EmptyAXTreeObserver : public ui::AXTreeObserver {
public:
- EmptyAXTreeDelegate() {}
-
- void OnNodeDataWillChange(ui::AXTree* tree,
- const ui::AXNodeData& old_node_data,
- const ui::AXNodeData& new_node_data) override {}
- void OnTreeDataChanged(ui::AXTree* tree,
- const ui::AXTreeData& old_data,
- const ui::AXTreeData& new_data) override {}
- void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override {}
- void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override {}
- void OnNodeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override {}
- void OnSubtreeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override {}
- void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override {}
- void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override {}
- void OnNodeChanged(ui::AXTree* tree, ui::AXNode* node) override {}
- void OnAtomicUpdateFinished(ui::AXTree* tree,
- bool root_changed,
- const std::vector<Change>& changes) override {}
+ EmptyAXTreeObserver() {}
+ ~EmptyAXTreeObserver() override{};
};
// Entry point for LibFuzzer.
@@ -44,10 +29,11 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
// Run with --v=1 to aid in debugging a specific crash.
VLOG(1) << "Input accessibility tree:\n" << initial_state.ToString();
- EmptyAXTreeDelegate delegate;
+ EmptyAXTreeObserver observer;
ui::AXTree tree;
- tree.SetDelegate(&delegate);
+ tree.AddObserver(&observer);
tree.Unserialize(initial_state);
+ tree.RemoveObserver(&observer);
return 0;
}
diff --git a/chromium/ui/accessibility/ax_tree_id.cc b/chromium/ui/accessibility/ax_tree_id.cc
index 6076f1122b5..2469e37ed97 100644
--- a/chromium/ui/accessibility/ax_tree_id.cc
+++ b/chromium/ui/accessibility/ax_tree_id.cc
@@ -7,56 +7,86 @@
#include <iostream>
#include "base/no_destructor.h"
+#include "base/value_conversions.h"
+#include "base/values.h"
namespace ui {
-AXTreeID::AXTreeID() : id_("") {}
+AXTreeID::AXTreeID() {}
-AXTreeID::AXTreeID(const std::string& string) : id_(string) {}
+AXTreeID::AXTreeID(const AXTreeID& other) = default;
+
+AXTreeID::AXTreeID(ax::mojom::AXTreeIDType type) : type_(type) {
+ if (type_ == ax::mojom::AXTreeIDType::kToken)
+ token_ = base::UnguessableToken::Create();
+}
+
+AXTreeID::AXTreeID(const std::string& string) {
+ if (string.empty()) {
+ type_ = ax::mojom::AXTreeIDType::kUnknown;
+ } else {
+ type_ = ax::mojom::AXTreeIDType::kToken;
+ base::Value string_value(string);
+ base::UnguessableToken token;
+ CHECK(base::GetValueAsUnguessableToken(string_value, &token));
+ token_ = token;
+ }
+}
// static
AXTreeID AXTreeID::FromString(const std::string& string) {
return AXTreeID(string);
}
+// static
+AXTreeID AXTreeID::CreateNewAXTreeID() {
+ return AXTreeID(ax::mojom::AXTreeIDType::kToken);
+}
+
+std::string AXTreeID::ToString() const {
+ switch (type_) {
+ case ax::mojom::AXTreeIDType::kUnknown:
+ return "";
+ case ax::mojom::AXTreeIDType::kToken:
+ return base::CreateUnguessableTokenValue(*token_).GetString();
+ }
+
+ NOTREACHED();
+ return std::string();
+}
+
bool AXTreeID::operator==(const AXTreeID& rhs) const {
- return id_ == rhs.id_;
+ return type_ == rhs.type_ && token_ == rhs.token_;
}
bool AXTreeID::operator!=(const AXTreeID& rhs) const {
- return id_ != rhs.id_;
+ return !(*this == rhs);
}
bool AXTreeID::operator<(const AXTreeID& rhs) const {
- return id_ < rhs.id_;
+ return std::tie(type_, token_) < std::tie(rhs.type_, rhs.token_);
}
bool AXTreeID::operator<=(const AXTreeID& rhs) const {
- return id_ <= rhs.id_;
+ return std::tie(type_, token_) <= std::tie(rhs.type_, rhs.token_);
}
bool AXTreeID::operator>(const AXTreeID& rhs) const {
- return id_ > rhs.id_;
+ return !(*this <= rhs);
}
bool AXTreeID::operator>=(const AXTreeID& rhs) const {
- return id_ >= rhs.id_;
+ return !(*this < rhs);
}
std::ostream& operator<<(std::ostream& stream, const AXTreeID& value) {
- return stream << 0;
+ return stream << value.ToString();
}
const AXTreeID& AXTreeIDUnknown() {
static const base::NoDestructor<AXTreeID> ax_tree_id_unknown(
- AXTreeID::FromString(""));
+ ax::mojom::AXTreeIDType::kUnknown);
return *ax_tree_id_unknown;
}
-const AXTreeID& DesktopAXTreeID() {
- static const base::NoDestructor<AXTreeID> desktop_ax_tree_id(
- AXTreeID::FromString("0"));
- return *desktop_ax_tree_id;
-}
-
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_id.h b/chromium/ui/accessibility/ax_tree_id.h
index 946181bbbf3..47490b3cae4 100644
--- a/chromium/ui/accessibility/ax_tree_id.h
+++ b/chromium/ui/accessibility/ax_tree_id.h
@@ -7,11 +7,13 @@
#include <string>
+#include "base/unguessable_token.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_export.h"
namespace mojo {
template <typename DataViewType, typename T>
-struct StructTraits;
+struct UnionTraits;
}
namespace ax {
@@ -25,10 +27,25 @@ namespace ui {
// A unique ID representing an accessibility tree.
class AX_EXPORT AXTreeID {
public:
+ // Create an Unknown AXTreeID.
AXTreeID();
+
+ // Copy constructor.
+ AXTreeID(const AXTreeID& other);
+
+ // Create a new unique AXTreeID.
+ static AXTreeID CreateNewAXTreeID();
+
+ // Unserialize an AXTreeID from a string. This is used so that tree IDs
+ // can be stored compactly as a string attribute in an AXNodeData, and
+ // so that AXTreeIDs can be passed to JavaScript bindings in the
+ // automation API.
static AXTreeID FromString(const std::string& string);
- const std::string& ToString() const { return id_; }
- operator std::string() const { return id_; }
+
+ std::string ToString() const;
+
+ ax::mojom::AXTreeIDType type() const { return type_; }
+ const base::Optional<base::UnguessableToken>& token() const { return token_; }
bool operator==(const AXTreeID& rhs) const;
bool operator!=(const AXTreeID& rhs) const;
@@ -38,11 +55,14 @@ class AX_EXPORT AXTreeID {
bool operator>=(const AXTreeID& rhs) const;
private:
+ explicit AXTreeID(ax::mojom::AXTreeIDType type);
explicit AXTreeID(const std::string& string);
- friend struct mojo::StructTraits<ax::mojom::AXTreeIDDataView, ui::AXTreeID>;
+ friend struct mojo::UnionTraits<ax::mojom::AXTreeIDDataView, ui::AXTreeID>;
+ friend class base::NoDestructor<AXTreeID>;
- std::string id_;
+ ax::mojom::AXTreeIDType type_ = ax::mojom::AXTreeIDType::kUnknown;
+ base::Optional<base::UnguessableToken> token_;
};
AX_EXPORT std::ostream& operator<<(std::ostream& stream, const AXTreeID& value);
@@ -50,9 +70,6 @@ AX_EXPORT std::ostream& operator<<(std::ostream& stream, const AXTreeID& value);
// The value to use when an AXTreeID is unknown.
AX_EXPORT extern const AXTreeID& AXTreeIDUnknown();
-// The AXTreeID of the desktop.
-AX_EXPORT extern const AXTreeID& DesktopAXTreeID();
-
} // namespace ui
#endif // UI_ACCESSIBILITY_AX_TREE_ID_H_
diff --git a/chromium/ui/accessibility/ax_tree_id_registry.cc b/chromium/ui/accessibility/ax_tree_id_registry.cc
index f0a47078aac..da654466e7c 100644
--- a/chromium/ui/accessibility/ax_tree_id_registry.cc
+++ b/chromium/ui/accessibility/ax_tree_id_registry.cc
@@ -6,7 +6,7 @@
#include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h"
-#include "ui/accessibility/ax_host_delegate.h"
+#include "ui/accessibility/ax_action_handler.h"
namespace ui {
@@ -15,21 +15,20 @@ AXTreeIDRegistry* AXTreeIDRegistry::GetInstance() {
return base::Singleton<AXTreeIDRegistry>::get();
}
-AXTreeID AXTreeIDRegistry::GetOrCreateAXTreeID(int process_id, int routing_id) {
- FrameID frame_id(process_id, routing_id);
+void AXTreeIDRegistry::SetFrameIDForAXTreeID(const FrameID& frame_id,
+ const AXTreeID& ax_tree_id) {
auto it = frame_to_ax_tree_id_map_.find(frame_id);
- if (it != frame_to_ax_tree_id_map_.end())
- return it->second;
-
- AXTreeID new_id =
- AXTreeID::FromString(base::IntToString(++ax_tree_id_counter_));
- frame_to_ax_tree_id_map_[frame_id] = new_id;
- ax_tree_to_frame_id_map_[new_id] = frame_id;
+ if (it != frame_to_ax_tree_id_map_.end()) {
+ NOTREACHED();
+ return;
+ }
- return new_id;
+ frame_to_ax_tree_id_map_[frame_id] = ax_tree_id;
+ ax_tree_to_frame_id_map_[ax_tree_id] = frame_id;
}
-AXTreeIDRegistry::FrameID AXTreeIDRegistry::GetFrameID(AXTreeID ax_tree_id) {
+AXTreeIDRegistry::FrameID AXTreeIDRegistry::GetFrameID(
+ const AXTreeID& ax_tree_id) {
auto it = ax_tree_to_frame_id_map_.find(ax_tree_id);
if (it != ax_tree_to_frame_id_map_.end())
return it->second;
@@ -37,44 +36,44 @@ AXTreeIDRegistry::FrameID AXTreeIDRegistry::GetFrameID(AXTreeID ax_tree_id) {
return FrameID(-1, -1);
}
-AXTreeID AXTreeIDRegistry::GetOrCreateAXTreeID(AXHostDelegate* delegate) {
- for (auto it : id_to_host_delegate_) {
- if (it.second == delegate)
+AXTreeID AXTreeIDRegistry::GetAXTreeID(AXTreeIDRegistry::FrameID frame_id) {
+ auto it = frame_to_ax_tree_id_map_.find(frame_id);
+ if (it != frame_to_ax_tree_id_map_.end())
+ return it->second;
+
+ return ui::AXTreeIDUnknown();
+}
+
+AXTreeID AXTreeIDRegistry::GetOrCreateAXTreeID(AXActionHandler* handler) {
+ for (auto it : id_to_action_handler_) {
+ if (it.second == handler)
return it.first;
}
- AXTreeID new_id =
- AXTreeID::FromString(base::IntToString(++ax_tree_id_counter_));
- id_to_host_delegate_[new_id] = delegate;
+ AXTreeID new_id = AXTreeID::CreateNewAXTreeID();
+ id_to_action_handler_[new_id] = handler;
return new_id;
}
-AXHostDelegate* AXTreeIDRegistry::GetHostDelegate(AXTreeID ax_tree_id) {
- auto it = id_to_host_delegate_.find(ax_tree_id);
- if (it == id_to_host_delegate_.end())
+AXActionHandler* AXTreeIDRegistry::GetActionHandler(AXTreeID ax_tree_id) {
+ auto it = id_to_action_handler_.find(ax_tree_id);
+ if (it == id_to_action_handler_.end())
return nullptr;
return it->second;
}
-void AXTreeIDRegistry::SetDelegateForID(AXHostDelegate* delegate, AXTreeID id) {
- id_to_host_delegate_[id] = delegate;
-}
-
void AXTreeIDRegistry::RemoveAXTreeID(AXTreeID ax_tree_id) {
auto frame_it = ax_tree_to_frame_id_map_.find(ax_tree_id);
if (frame_it != ax_tree_to_frame_id_map_.end()) {
frame_to_ax_tree_id_map_.erase(frame_it->second);
ax_tree_to_frame_id_map_.erase(frame_it);
- return;
}
- auto action_it = id_to_host_delegate_.find(ax_tree_id);
- if (action_it != id_to_host_delegate_.end())
- id_to_host_delegate_.erase(action_it);
+ auto action_it = id_to_action_handler_.find(ax_tree_id);
+ if (action_it != id_to_action_handler_.end())
+ id_to_action_handler_.erase(action_it);
}
-AXTreeIDRegistry::AXTreeIDRegistry() : ax_tree_id_counter_(-1) {
- // Always populate default desktop tree value (0 -> 0, 0).
- GetOrCreateAXTreeID(0, 0);
+AXTreeIDRegistry::AXTreeIDRegistry() {
}
AXTreeIDRegistry::~AXTreeIDRegistry() {}
diff --git a/chromium/ui/accessibility/ax_tree_id_registry.h b/chromium/ui/accessibility/ax_tree_id_registry.h
index 24e40bd1fc3..44405bd7c69 100644
--- a/chromium/ui/accessibility/ax_tree_id_registry.h
+++ b/chromium/ui/accessibility/ax_tree_id_registry.h
@@ -20,12 +20,12 @@ struct DefaultSingletonTraits;
namespace ui {
-class AXHostDelegate;
+class AXActionHandler;
// This class generates and saves a runtime id for an accessibility tree.
// It provides a few distinct forms of generating an id:
// - from a frame id (which consists of a process and routing id)
-// - from a backing |AXHostDelegate| object
+// - from a backing |AXActionHandler| object
//
// The first form allows underlying instances to change but refer to the same
// frame.
@@ -37,37 +37,41 @@ class AX_EXPORT AXTreeIDRegistry {
// Get the single instance of this class.
static AXTreeIDRegistry* GetInstance();
- // Methods for FrameID ax tree id generation, and retrieval.
- AXTreeID GetOrCreateAXTreeID(int process_id, int routing_id);
- FrameID GetFrameID(AXTreeID ax_tree_id);
+ // Gets the frame id based on an ax tree id.
+ FrameID GetFrameID(const AXTreeID& ax_tree_id);
- // Retrieve an |AXHostDelegate|.
- AXHostDelegate* GetHostDelegate(AXTreeID ax_tree_id);
+ // Gets an ax tree id from a frame id.
+ AXTreeID GetAXTreeID(FrameID frame_id);
+ // Retrieve an |AXActionHandler| based on an ax tree id.
+ AXActionHandler* GetActionHandler(AXTreeID ax_tree_id);
+
+ // Removes an ax tree id, and its associated delegate and frame id (if it
+ // exists).
void RemoveAXTreeID(AXTreeID ax_tree_id);
+ // Associate a frame id with an ax tree id.
+ void SetFrameIDForAXTreeID(const FrameID& frame_id,
+ const AXTreeID& ax_tree_id);
+
private:
friend struct base::DefaultSingletonTraits<AXTreeIDRegistry>;
- friend AXHostDelegate;
+ friend AXActionHandler;
- // Methods for AXHostDelegate ax tree id generation.
- AXTreeID GetOrCreateAXTreeID(AXHostDelegate* delegate);
- void SetDelegateForID(AXHostDelegate* delegate, AXTreeID id);
+ // Get or create a ax tree id keyed on |handler|.
+ AXTreeID GetOrCreateAXTreeID(AXActionHandler* handler);
AXTreeIDRegistry();
virtual ~AXTreeIDRegistry();
- // Tracks the current unique ax tree id.
- int ax_tree_id_counter_;
-
// Maps an accessibility tree to its frame via ids.
std::map<AXTreeID, FrameID> ax_tree_to_frame_id_map_;
// Maps frames to an accessibility tree via ids.
std::map<FrameID, AXTreeID> frame_to_ax_tree_id_map_;
- // Maps an id to its host delegate.
- std::map<AXTreeID, AXHostDelegate*> id_to_host_delegate_;
+ // Maps an id to its handler.
+ std::map<AXTreeID, AXActionHandler*> id_to_action_handler_;
DISALLOW_COPY_AND_ASSIGN(AXTreeIDRegistry);
};
diff --git a/chromium/ui/accessibility/ax_tree_observer.cc b/chromium/ui/accessibility/ax_tree_observer.cc
new file mode 100644
index 00000000000..9080e81159f
--- /dev/null
+++ b/chromium/ui/accessibility/ax_tree_observer.cc
@@ -0,0 +1,12 @@
+// 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_tree_observer.h"
+
+namespace ui {
+
+AXTreeObserver::AXTreeObserver() = default;
+AXTreeObserver::~AXTreeObserver() = default;
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_observer.h b/chromium/ui/accessibility/ax_tree_observer.h
new file mode 100644
index 00000000000..7c38cf9954e
--- /dev/null
+++ b/chromium/ui/accessibility/ax_tree_observer.h
@@ -0,0 +1,152 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_TREE_OBSERVER_H_
+#define UI_ACCESSIBILITY_AX_TREE_OBSERVER_H_
+
+#include "base/observer_list_types.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+
+class AXNode;
+struct AXNodeData;
+class AXTree;
+struct AXTreeData;
+
+// Used when you want to be notified when changes happen to an AXTree.
+//
+// Some of the notifications are called in the middle of an update operation.
+// Be careful, as the tree may be in an inconsistent state at this time;
+// don't walk the parents and children at this time:
+// OnNodeWillBeDeleted
+// OnSubtreeWillBeDeleted
+// OnNodeWillBeReparented
+// OnSubtreeWillBeReparented
+// OnNodeCreated
+// OnNodeReparented
+// OnNodeChanged
+//
+// In addition, one additional notification is fired at the end of an
+// atomic update, and it provides a vector of nodes that were added or
+// changed, for final postprocessing:
+// OnAtomicUpdateFinished
+//
+class AX_EXPORT AXTreeObserver : public base::CheckedObserver {
+ public:
+ AXTreeObserver();
+ ~AXTreeObserver() override;
+
+ // Called before a node's data gets updated.
+ virtual void OnNodeDataWillChange(AXTree* tree,
+ const AXNodeData& old_node_data,
+ const AXNodeData& new_node_data) {}
+
+ // Individual callbacks for every attribute of AXNodeData that can change.
+ virtual void OnRoleChanged(AXTree* tree,
+ AXNode* node,
+ ax::mojom::Role old_role,
+ ax::mojom::Role new_role) {}
+ virtual void OnStateChanged(AXTree* tree,
+ AXNode* node,
+ ax::mojom::State state,
+ bool new_value) {}
+ virtual void OnStringAttributeChanged(AXTree* tree,
+ AXNode* node,
+ ax::mojom::StringAttribute attr,
+ const std::string& old_value,
+ const std::string& new_value) {}
+ virtual void OnIntAttributeChanged(AXTree* tree,
+ AXNode* node,
+ ax::mojom::IntAttribute attr,
+ int32_t old_value,
+ int32_t new_value) {}
+ virtual void OnFloatAttributeChanged(AXTree* tree,
+ AXNode* node,
+ ax::mojom::FloatAttribute attr,
+ float old_value,
+ float new_value) {}
+ virtual void OnBoolAttributeChanged(AXTree* tree,
+ AXNode* node,
+ ax::mojom::BoolAttribute attr,
+ bool new_value) {}
+ virtual void OnIntListAttributeChanged(
+ AXTree* tree,
+ AXNode* node,
+ ax::mojom::IntListAttribute attr,
+ const std::vector<int32_t>& old_value,
+ const std::vector<int32_t>& new_value) {}
+ virtual void OnStringListAttributeChanged(
+ AXTree* tree,
+ AXNode* node,
+ ax::mojom::StringListAttribute attr,
+ const std::vector<std::string>& old_value,
+ const std::vector<std::string>& new_value) {}
+
+ // Called when tree data changes.
+ virtual void OnTreeDataChanged(AXTree* tree,
+ const ui::AXTreeData& old_data,
+ const ui::AXTreeData& new_data) {}
+
+ // Called just before a node is deleted. Its id and data will be valid,
+ // but its links to parents and children are invalid. This is called
+ // in the middle of an update, the tree may be in an invalid state!
+ virtual void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) {}
+
+ // Same as OnNodeWillBeDeleted, but only called once for an entire subtree.
+ // This is called in the middle of an update, the tree may be in an
+ // invalid state!
+ virtual void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) {}
+
+ // Called just before a node is deleted for reparenting. See
+ // |OnNodeWillBeDeleted| for additional information.
+ virtual void OnNodeWillBeReparented(AXTree* tree, AXNode* node) {}
+
+ // Called just before a subtree is deleted for reparenting. See
+ // |OnSubtreeWillBeDeleted| for additional information.
+ virtual void OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) {}
+
+ // Called immediately after a new node is created. The tree may be in
+ // the middle of an update, don't walk the parents and children now.
+ virtual void OnNodeCreated(AXTree* tree, AXNode* node) {}
+
+ // Called immediately after a node is reparented. The tree may be in the
+ // middle of an update, don't walk the parents and children now.
+ virtual void OnNodeReparented(AXTree* tree, AXNode* node) {}
+
+ // Called when a node changes its data or children. The tree may be in
+ // the middle of an update, don't walk the parents and children now.
+ virtual void OnNodeChanged(AXTree* tree, AXNode* node) {}
+
+ enum ChangeType {
+ NODE_CREATED,
+ SUBTREE_CREATED,
+ NODE_CHANGED,
+ NODE_REPARENTED,
+ SUBTREE_REPARENTED
+ };
+
+ struct Change {
+ Change(AXNode* node, ChangeType type) {
+ this->node = node;
+ this->type = type;
+ }
+ AXNode* node;
+ ChangeType type;
+ };
+
+ // Called at the end of the update operation. Every node that was added
+ // or changed will be included in |changes|, along with an enum indicating
+ // the type of change - either (1) a node was created, (2) a node was created
+ // and it's the root of a new subtree, or (3) a node was changed. Finally,
+ // a bool indicates if the root of the tree was changed or not.
+ virtual void OnAtomicUpdateFinished(AXTree* tree,
+ bool root_changed,
+ const std::vector<Change>& changes) {}
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_TREE_OBSERVER_H_
diff --git a/chromium/ui/accessibility/ax_tree_serializer.h b/chromium/ui/accessibility/ax_tree_serializer.h
index f11ded45a69..6875d414453 100644
--- a/chromium/ui/accessibility/ax_tree_serializer.h
+++ b/chromium/ui/accessibility/ax_tree_serializer.h
@@ -8,9 +8,10 @@
#include <stddef.h>
#include <stdint.h>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
-#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree_source.h"
@@ -169,9 +170,6 @@ class AXTreeSerializer {
AXSourceNode node,
AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update);
- // Visit all of the descendants of |node| once.
- void WalkAllDescendants(AXSourceNode node);
-
// Delete the entire client subtree but don't set the did_reset_ flag
// like when Reset() is called.
void InternalReset();
@@ -186,7 +184,7 @@ class AXTreeSerializer {
ClientTreeNode* client_root_ = nullptr;
// A map from IDs to nodes in the client tree.
- base::hash_map<int32_t, ClientTreeNode*> client_id_map_;
+ std::unordered_map<int32_t, ClientTreeNode*> client_id_map_;
// The maximum number of nodes to serialize in a given call to
// SerializeChanges, or 0 if there's no maximum.
@@ -350,7 +348,7 @@ template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
ClientTreeNode*
AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::ClientTreeNodeById(
int32_t id) {
- base::hash_map<int32_t, ClientTreeNode*>::iterator iter =
+ std::unordered_map<int32_t, ClientTreeNode*>::iterator iter =
client_id_map_.find(id);
if (iter != client_id_map_.end())
return iter->second;
@@ -413,12 +411,6 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::SerializeChanges(
if (!tree_->IsValid(lca))
lca = tree_->GetRoot();
- // Work around flaky source trees where nodes don't figure out their
- // correct parent/child relationships until you walk the whole tree once.
- // Covered by this test in the content_browsertests suite:
- // DumpAccessibilityTreeTest.AccessibilityAriaOwns.
- WalkAllDescendants(lca);
-
if (!SerializeChangedNodes(lca, out_update))
return false;
@@ -505,7 +497,7 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
// If we've hit the maximum number of serialized nodes, pretend
// this node has no children but keep going so that we get
// consistent results.
- base::hash_set<int32_t> new_child_ids;
+ std::unordered_set<int32_t> new_child_ids;
std::vector<AXSourceNode> children;
if (max_node_count_ == 0 || out_update->nodes.size() < max_node_count_) {
tree_->GetChildren(node, &children);
@@ -526,6 +518,7 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
// above. If this happens, reset and return an error.
ClientTreeNode* client_child = client_id_map_[new_child_id];
if (client_child && client_child->parent != client_node) {
+ DVLOG(1) << "Reparenting detected";
Reset();
return false;
}
@@ -537,7 +530,7 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
// first in a separate pass so that nodes that are reparented
// don't end up children of two different parents in the middle
// of an update, which can lead to a double-free.
- base::hash_map<int32_t, ClientTreeNode*> client_child_id_map;
+ std::unordered_map<int32_t, ClientTreeNode*> client_child_id_map;
std::vector<ClientTreeNode*> old_children;
old_children.swap(client_node->children);
for (size_t i = 0; i < old_children.size(); ++i) {
@@ -614,15 +607,6 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
return true;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::WalkAllDescendants(
- AXSourceNode node) {
- std::vector<AXSourceNode> children;
- tree_->GetChildren(node, &children);
- for (size_t i = 0; i < children.size(); ++i)
- WalkAllDescendants(children[i]);
-}
-
} // namespace ui
#endif // UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
diff --git a/chromium/ui/accessibility/ax_tree_source_checker.h b/chromium/ui/accessibility/ax_tree_source_checker.h
new file mode 100644
index 00000000000..f0b1a12baa6
--- /dev/null
+++ b/chromium/ui/accessibility/ax_tree_source_checker.h
@@ -0,0 +1,155 @@
+// 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_TREE_SOURCE_CHECKER_H_
+#define UI_ACCESSIBILITY_AX_TREE_SOURCE_CHECKER_H_
+
+#include "base/strings/string_number_conversions.h"
+#include "ui/accessibility/ax_tree_source.h"
+
+namespace ui {
+
+template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
+class AXTreeSourceChecker {
+ public:
+ explicit AXTreeSourceChecker(
+ AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree);
+ ~AXTreeSourceChecker();
+
+ // Returns true if everything reachable from the root of the tree is
+ // consistent in its parent/child connections.
+ bool Check();
+
+ private:
+ bool Check(AXSourceNode node, std::string indent, std::string* output);
+
+ AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree_;
+
+ std::map<int32_t, int32_t> node_id_to_parent_id_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXTreeSourceChecker);
+};
+
+template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
+AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::AXTreeSourceChecker(
+ AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree)
+ : tree_(tree) {}
+
+template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
+AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::
+ ~AXTreeSourceChecker() = default;
+
+template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
+bool AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::Check() {
+ node_id_to_parent_id_map_.clear();
+
+ AXSourceNode root = tree_->GetRoot();
+ if (!tree_->IsValid(root)) {
+ LOG(ERROR) << "AXTreeSource root is not valid.";
+ return false;
+ }
+
+ int32_t root_id = tree_->GetId(root);
+ node_id_to_parent_id_map_[root_id] = -1;
+
+ std::string output;
+ bool success = Check(root, "", &output);
+ if (!success)
+ LOG(ERROR) << "AXTreeSource is inconsistent.\n" << output << "\n\n";
+
+ return success;
+}
+
+template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
+bool AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::Check(
+ AXSourceNode node,
+ std::string indent,
+ std::string* output) {
+ *output += indent;
+ AXNodeData node_data;
+ tree_->SerializeNode(node, &node_data);
+ *output += node_data.ToString();
+
+ int32_t node_id = tree_->GetId(node);
+ if (node_id <= 0) {
+ LOG(ERROR) << "Got a node with id " << node_id
+ << ", but all node IDs should be >= 1.";
+ return false;
+ }
+
+ // Check parent.
+ int32_t expected_parent_id = node_id_to_parent_id_map_[node_id];
+ AXSourceNode parent = tree_->GetParent(node);
+ if (expected_parent_id == -1) {
+ if (tree_->IsValid(parent)) {
+ LOG(ERROR) << "Node " << node_id << " is the root, so its parent "
+ << "should be invalid, but we got a node with id "
+ << tree_->GetId(parent);
+ return false;
+ }
+ } else {
+ if (!tree_->IsValid(parent)) {
+ LOG(ERROR) << "Node " << node_id << " is not the root, but its "
+ << "parent was invalid.";
+ return false;
+ }
+ int32_t parent_id = tree_->GetId(parent);
+ if (parent_id != expected_parent_id) {
+ LOG(ERROR) << "Expected node " << node_id << " to have a parent of "
+ << expected_parent_id << ", but found a parent of "
+ << parent_id;
+ return false;
+ }
+ }
+
+ // Check children.
+ std::vector<AXSourceNode> children;
+ tree_->GetChildren(node, &children);
+
+ if (children.size() == 0)
+ *output += " (no children)";
+
+ for (size_t i = 0; i < children.size(); i++) {
+ auto& child = children[i];
+ if (!tree_->IsValid(child)) {
+ LOG(ERROR) << "Node " << node_id << " has an invalid child.";
+ return false;
+ }
+
+ int32_t child_id = tree_->GetId(child);
+ if (i == 0)
+ *output += " child_ids=" + base::IntToString(child_id);
+ else
+ *output += "," + base::IntToString(child_id);
+
+ if (node_id_to_parent_id_map_.find(child_id) !=
+ node_id_to_parent_id_map_.end()) {
+ *output += "\n" + indent + " ";
+ AXNodeData child_data;
+ tree_->SerializeNode(child, &child_data);
+ *output += child_data.ToString() + "\n";
+
+ LOG(ERROR) << "Node " << node_id << " has a child with ID " << child_id
+ << ", but we've previously seen a node "
+ << " with that ID, with a parent of "
+ << node_id_to_parent_id_map_[child_id];
+ return false;
+ }
+
+ node_id_to_parent_id_map_[child_id] = node_id;
+ }
+
+ *output += "\n";
+
+ for (auto& child : children) {
+ if (!Check(child, indent + " ", output))
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_TREE_SOURCE_CHECKER_H_
diff --git a/chromium/ui/accessibility/ax_tree_unittest.cc b/chromium/ui/accessibility/ax_tree_unittest.cc
index 109eda97e8f..d92c2a6ac0c 100644
--- a/chromium/ui/accessibility/ax_tree_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_unittest.cc
@@ -16,6 +16,7 @@
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_serializable_tree.h"
+#include "ui/accessibility/ax_tree_observer.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/gfx/transform.h"
@@ -54,11 +55,13 @@ bool IsNodeOffscreen(const AXTree& tree, int32_t id) {
return result;
}
-class FakeAXTreeDelegate : public AXTreeDelegate {
+class TestAXTreeObserver : public AXTreeObserver {
public:
- FakeAXTreeDelegate()
- : tree_data_changed_(false),
- root_changed_(false) {}
+ TestAXTreeObserver(AXTree* tree)
+ : tree_(tree), tree_data_changed_(false), root_changed_(false) {
+ tree_->AddObserver(this);
+ }
+ ~TestAXTreeObserver() final { tree_->RemoveObserver(this); }
void OnNodeDataWillChange(AXTree* tree,
const AXNodeData& old_node_data,
@@ -210,6 +213,7 @@ class FakeAXTreeDelegate : public AXTreeDelegate {
}
private:
+ AXTree* tree_;
bool tree_data_changed_;
bool root_changed_;
std::vector<int32_t> deleted_ids_;
@@ -431,29 +435,26 @@ TEST(AXTreeTest, NoReparentingOfRootIfNoNewRoot) {
update.node_id_to_clear = root.id;
update.nodes = {root, child1, child2};
- FakeAXTreeDelegate fake_delegate;
- tree.SetDelegate(&fake_delegate);
+ TestAXTreeObserver test_observer(&tree);
ASSERT_TRUE(tree.Unserialize(update));
- EXPECT_EQ(0U, fake_delegate.deleted_ids().size());
- EXPECT_EQ(0U, fake_delegate.subtree_deleted_ids().size());
- EXPECT_EQ(0U, fake_delegate.created_ids().size());
-
- EXPECT_EQ(0U, fake_delegate.node_creation_finished_ids().size());
- EXPECT_EQ(0U, fake_delegate.subtree_creation_finished_ids().size());
- EXPECT_EQ(0U, fake_delegate.node_reparented_finished_ids().size());
+ EXPECT_EQ(0U, test_observer.deleted_ids().size());
+ EXPECT_EQ(0U, test_observer.subtree_deleted_ids().size());
+ EXPECT_EQ(0U, test_observer.created_ids().size());
- ASSERT_EQ(2U, fake_delegate.subtree_reparented_finished_ids().size());
- EXPECT_EQ(child1.id, fake_delegate.subtree_reparented_finished_ids()[0]);
- EXPECT_EQ(child2.id, fake_delegate.subtree_reparented_finished_ids()[1]);
+ EXPECT_EQ(0U, test_observer.node_creation_finished_ids().size());
+ EXPECT_EQ(0U, test_observer.subtree_creation_finished_ids().size());
+ EXPECT_EQ(0U, test_observer.node_reparented_finished_ids().size());
- ASSERT_EQ(1U, fake_delegate.change_finished_ids().size());
- EXPECT_EQ(root.id, fake_delegate.change_finished_ids()[0]);
+ ASSERT_EQ(2U, test_observer.subtree_reparented_finished_ids().size());
+ EXPECT_EQ(child1.id, test_observer.subtree_reparented_finished_ids()[0]);
+ EXPECT_EQ(child2.id, test_observer.subtree_reparented_finished_ids()[1]);
- EXPECT_FALSE(fake_delegate.root_changed());
- EXPECT_FALSE(fake_delegate.tree_data_changed());
+ ASSERT_EQ(1U, test_observer.change_finished_ids().size());
+ EXPECT_EQ(root.id, test_observer.change_finished_ids()[0]);
- tree.SetDelegate(nullptr);
+ EXPECT_FALSE(test_observer.root_changed());
+ EXPECT_FALSE(test_observer.tree_data_changed());
}
TEST(AXTreeTest, ReparentRootIfRootChanged) {
@@ -484,39 +485,36 @@ TEST(AXTreeTest, ReparentRootIfRootChanged) {
update.node_id_to_clear = root.id;
update.nodes = {root2, child1, child2};
- FakeAXTreeDelegate fake_delegate;
- tree.SetDelegate(&fake_delegate);
+ TestAXTreeObserver test_observer(&tree);
ASSERT_TRUE(tree.Unserialize(update));
- ASSERT_EQ(1U, fake_delegate.deleted_ids().size());
- EXPECT_EQ(root.id, fake_delegate.deleted_ids()[0]);
-
- ASSERT_EQ(1U, fake_delegate.subtree_deleted_ids().size());
- EXPECT_EQ(root.id, fake_delegate.subtree_deleted_ids()[0]);
+ ASSERT_EQ(1U, test_observer.deleted_ids().size());
+ EXPECT_EQ(root.id, test_observer.deleted_ids()[0]);
- ASSERT_EQ(1U, fake_delegate.created_ids().size());
- EXPECT_EQ(root2.id, fake_delegate.created_ids()[0]);
+ ASSERT_EQ(1U, test_observer.subtree_deleted_ids().size());
+ EXPECT_EQ(root.id, test_observer.subtree_deleted_ids()[0]);
- EXPECT_EQ(0U, fake_delegate.node_creation_finished_ids().size());
+ ASSERT_EQ(1U, test_observer.created_ids().size());
+ EXPECT_EQ(root2.id, test_observer.created_ids()[0]);
- ASSERT_EQ(1U, fake_delegate.subtree_creation_finished_ids().size());
- EXPECT_EQ(root2.id, fake_delegate.subtree_creation_finished_ids()[0]);
+ EXPECT_EQ(0U, test_observer.node_creation_finished_ids().size());
- ASSERT_EQ(2U, fake_delegate.node_reparented_finished_ids().size());
- EXPECT_EQ(child1.id, fake_delegate.node_reparented_finished_ids()[0]);
- EXPECT_EQ(child2.id, fake_delegate.node_reparented_finished_ids()[1]);
+ ASSERT_EQ(1U, test_observer.subtree_creation_finished_ids().size());
+ EXPECT_EQ(root2.id, test_observer.subtree_creation_finished_ids()[0]);
- EXPECT_EQ(0U, fake_delegate.subtree_reparented_finished_ids().size());
+ ASSERT_EQ(2U, test_observer.node_reparented_finished_ids().size());
+ EXPECT_EQ(child1.id, test_observer.node_reparented_finished_ids()[0]);
+ EXPECT_EQ(child2.id, test_observer.node_reparented_finished_ids()[1]);
- EXPECT_EQ(0U, fake_delegate.change_finished_ids().size());
+ EXPECT_EQ(0U, test_observer.subtree_reparented_finished_ids().size());
- EXPECT_TRUE(fake_delegate.root_changed());
- EXPECT_FALSE(fake_delegate.tree_data_changed());
+ EXPECT_EQ(0U, test_observer.change_finished_ids().size());
- tree.SetDelegate(nullptr);
+ EXPECT_TRUE(test_observer.root_changed());
+ EXPECT_FALSE(test_observer.tree_data_changed());
}
-TEST(AXTreeTest, TreeDelegateIsCalled) {
+TEST(AXTreeTest, TreeObserverIsCalled) {
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(2);
@@ -533,34 +531,30 @@ TEST(AXTreeTest, TreeDelegateIsCalled) {
update.nodes[0].child_ids.push_back(4);
update.nodes[1].id = 4;
- FakeAXTreeDelegate fake_delegate;
- tree.SetDelegate(&fake_delegate);
-
+ TestAXTreeObserver test_observer(&tree);
ASSERT_TRUE(tree.Unserialize(update));
- ASSERT_EQ(2U, fake_delegate.deleted_ids().size());
- EXPECT_EQ(1, fake_delegate.deleted_ids()[0]);
- EXPECT_EQ(2, fake_delegate.deleted_ids()[1]);
-
- ASSERT_EQ(1U, fake_delegate.subtree_deleted_ids().size());
- EXPECT_EQ(1, fake_delegate.subtree_deleted_ids()[0]);
+ ASSERT_EQ(2U, test_observer.deleted_ids().size());
+ EXPECT_EQ(1, test_observer.deleted_ids()[0]);
+ EXPECT_EQ(2, test_observer.deleted_ids()[1]);
- ASSERT_EQ(2U, fake_delegate.created_ids().size());
- EXPECT_EQ(3, fake_delegate.created_ids()[0]);
- EXPECT_EQ(4, fake_delegate.created_ids()[1]);
+ ASSERT_EQ(1U, test_observer.subtree_deleted_ids().size());
+ EXPECT_EQ(1, test_observer.subtree_deleted_ids()[0]);
- ASSERT_EQ(1U, fake_delegate.subtree_creation_finished_ids().size());
- EXPECT_EQ(3, fake_delegate.subtree_creation_finished_ids()[0]);
+ ASSERT_EQ(2U, test_observer.created_ids().size());
+ EXPECT_EQ(3, test_observer.created_ids()[0]);
+ EXPECT_EQ(4, test_observer.created_ids()[1]);
- ASSERT_EQ(1U, fake_delegate.node_creation_finished_ids().size());
- EXPECT_EQ(4, fake_delegate.node_creation_finished_ids()[0]);
+ ASSERT_EQ(1U, test_observer.subtree_creation_finished_ids().size());
+ EXPECT_EQ(3, test_observer.subtree_creation_finished_ids()[0]);
- ASSERT_TRUE(fake_delegate.root_changed());
+ ASSERT_EQ(1U, test_observer.node_creation_finished_ids().size());
+ EXPECT_EQ(4, test_observer.node_creation_finished_ids()[0]);
- tree.SetDelegate(nullptr);
+ ASSERT_TRUE(test_observer.root_changed());
}
-TEST(AXTreeTest, TreeDelegateIsCalledForTreeDataChanges) {
+TEST(AXTreeTest, TreeObserverIsCalledForTreeDataChanges) {
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(1);
@@ -569,13 +563,12 @@ TEST(AXTreeTest, TreeDelegateIsCalledForTreeDataChanges) {
initial_state.tree_data.title = "Initial";
AXTree tree(initial_state);
- FakeAXTreeDelegate fake_delegate;
- tree.SetDelegate(&fake_delegate);
+ TestAXTreeObserver test_observer(&tree);
// An empty update shouldn't change tree data.
AXTreeUpdate empty_update;
EXPECT_TRUE(tree.Unserialize(empty_update));
- EXPECT_FALSE(fake_delegate.tree_data_changed());
+ EXPECT_FALSE(test_observer.tree_data_changed());
EXPECT_EQ("Initial", tree.data().title);
// An update with tree data shouldn't change tree data if
@@ -583,7 +576,7 @@ TEST(AXTreeTest, TreeDelegateIsCalledForTreeDataChanges) {
AXTreeUpdate ignored_tree_data_update;
ignored_tree_data_update.tree_data.title = "Ignore Me";
EXPECT_TRUE(tree.Unserialize(ignored_tree_data_update));
- EXPECT_FALSE(fake_delegate.tree_data_changed());
+ EXPECT_FALSE(test_observer.tree_data_changed());
EXPECT_EQ("Initial", tree.data().title);
// An update with |has_tree_data| set should update the tree data.
@@ -591,10 +584,8 @@ TEST(AXTreeTest, TreeDelegateIsCalledForTreeDataChanges) {
tree_data_update.has_tree_data = true;
tree_data_update.tree_data.title = "New Title";
EXPECT_TRUE(tree.Unserialize(tree_data_update));
- EXPECT_TRUE(fake_delegate.tree_data_changed());
+ EXPECT_TRUE(test_observer.tree_data_changed());
EXPECT_EQ("New Title", tree.data().title);
-
- tree.SetDelegate(nullptr);
}
TEST(AXTreeTest, ReparentingDoesNotTriggerNodeCreated) {
@@ -607,9 +598,8 @@ TEST(AXTreeTest, ReparentingDoesNotTriggerNodeCreated) {
initial_state.nodes[1].child_ids.push_back(3);
initial_state.nodes[2].id = 3;
- FakeAXTreeDelegate fake_delegate;
AXTree tree(initial_state);
- tree.SetDelegate(&fake_delegate);
+ TestAXTreeObserver test_observer(&tree);
AXTreeUpdate update;
update.nodes.resize(2);
@@ -619,17 +609,17 @@ TEST(AXTreeTest, ReparentingDoesNotTriggerNodeCreated) {
update.nodes[0].child_ids.push_back(3);
update.nodes[1].id = 3;
EXPECT_TRUE(tree.Unserialize(update)) << tree.error();
- std::vector<int> created = fake_delegate.node_creation_finished_ids();
+ std::vector<int> created = test_observer.node_creation_finished_ids();
std::vector<int> subtree_reparented =
- fake_delegate.subtree_reparented_finished_ids();
+ test_observer.subtree_reparented_finished_ids();
std::vector<int> node_reparented =
- fake_delegate.node_reparented_finished_ids();
+ test_observer.node_reparented_finished_ids();
ASSERT_FALSE(base::ContainsValue(created, 3));
ASSERT_TRUE(base::ContainsValue(subtree_reparented, 3));
ASSERT_FALSE(base::ContainsValue(node_reparented, 3));
}
-TEST(AXTreeTest, TreeDelegateIsNotCalledForReparenting) {
+TEST(AXTreeTest, TreeObserverIsNotCalledForReparenting) {
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(2);
@@ -646,32 +636,29 @@ TEST(AXTreeTest, TreeDelegateIsNotCalledForReparenting) {
update.nodes[0].child_ids.push_back(4);
update.nodes[1].id = 4;
- FakeAXTreeDelegate fake_delegate;
- tree.SetDelegate(&fake_delegate);
+ TestAXTreeObserver test_observer(&tree);
EXPECT_TRUE(tree.Unserialize(update));
- ASSERT_EQ(1U, fake_delegate.deleted_ids().size());
- EXPECT_EQ(1, fake_delegate.deleted_ids()[0]);
-
- ASSERT_EQ(1U, fake_delegate.subtree_deleted_ids().size());
- EXPECT_EQ(1, fake_delegate.subtree_deleted_ids()[0]);
+ ASSERT_EQ(1U, test_observer.deleted_ids().size());
+ EXPECT_EQ(1, test_observer.deleted_ids()[0]);
- ASSERT_EQ(1U, fake_delegate.created_ids().size());
- EXPECT_EQ(4, fake_delegate.created_ids()[0]);
+ ASSERT_EQ(1U, test_observer.subtree_deleted_ids().size());
+ EXPECT_EQ(1, test_observer.subtree_deleted_ids()[0]);
- ASSERT_EQ(1U, fake_delegate.subtree_creation_finished_ids().size());
- EXPECT_EQ(4, fake_delegate.subtree_creation_finished_ids()[0]);
+ ASSERT_EQ(1U, test_observer.created_ids().size());
+ EXPECT_EQ(4, test_observer.created_ids()[0]);
- ASSERT_EQ(1U, fake_delegate.subtree_reparented_finished_ids().size());
- EXPECT_EQ(2, fake_delegate.subtree_reparented_finished_ids()[0]);
+ ASSERT_EQ(1U, test_observer.subtree_creation_finished_ids().size());
+ EXPECT_EQ(4, test_observer.subtree_creation_finished_ids()[0]);
- EXPECT_EQ(0U, fake_delegate.node_creation_finished_ids().size());
- EXPECT_EQ(0U, fake_delegate.node_reparented_finished_ids().size());
+ ASSERT_EQ(1U, test_observer.subtree_reparented_finished_ids().size());
+ EXPECT_EQ(2, test_observer.subtree_reparented_finished_ids()[0]);
- ASSERT_TRUE(fake_delegate.root_changed());
+ EXPECT_EQ(0U, test_observer.node_creation_finished_ids().size());
+ EXPECT_EQ(0U, test_observer.node_reparented_finished_ids().size());
- tree.SetDelegate(nullptr);
+ ASSERT_TRUE(test_observer.root_changed());
}
// UAF caught by ax_tree_fuzzer
@@ -728,8 +715,7 @@ TEST(AXTreeTest, RoleAndStateChangeCallbacks) {
initial_state.nodes[0].AddState(ax::mojom::State::kFocusable);
AXTree tree(initial_state);
- FakeAXTreeDelegate fake_delegate;
- tree.SetDelegate(&fake_delegate);
+ TestAXTreeObserver test_observer(&tree);
// Change the role and state.
AXTreeUpdate update;
@@ -743,13 +729,11 @@ TEST(AXTreeTest, RoleAndStateChangeCallbacks) {
EXPECT_TRUE(tree.Unserialize(update));
const std::vector<std::string>& change_log =
- fake_delegate.attribute_change_log();
+ test_observer.attribute_change_log();
ASSERT_EQ(3U, change_log.size());
EXPECT_EQ("Role changed from button to checkBox", change_log[0]);
EXPECT_EQ("visited changed to true", change_log[1]);
EXPECT_EQ("checkedState changed from 2 to 1", change_log[2]);
-
- tree.SetDelegate(nullptr);
}
TEST(AXTreeTest, AttributeChangeCallbacks) {
@@ -776,8 +760,7 @@ TEST(AXTreeTest, AttributeChangeCallbacks) {
1);
AXTree tree(initial_state);
- FakeAXTreeDelegate fake_delegate;
- tree.SetDelegate(&fake_delegate);
+ TestAXTreeObserver test_observer(&tree);
// Change existing attributes.
AXTreeUpdate update0;
@@ -801,7 +784,7 @@ TEST(AXTreeTest, AttributeChangeCallbacks) {
EXPECT_TRUE(tree.Unserialize(update0));
const std::vector<std::string>& change_log =
- fake_delegate.attribute_change_log();
+ test_observer.attribute_change_log();
ASSERT_EQ(9U, change_log.size());
EXPECT_EQ("name changed from N1 to N2", change_log[0]);
EXPECT_EQ("description changed from D1 to D2", change_log[1]);
@@ -813,8 +796,7 @@ TEST(AXTreeTest, AttributeChangeCallbacks) {
EXPECT_EQ("scrollX changed from 5 to 6", change_log[7]);
EXPECT_EQ("scrollXMin changed from 1 to 2", change_log[8]);
- FakeAXTreeDelegate fake_delegate2;
- tree.SetDelegate(&fake_delegate2);
+ TestAXTreeObserver test_observer2(&tree);
// Add and remove attributes.
AXTreeUpdate update1;
@@ -834,7 +816,7 @@ TEST(AXTreeTest, AttributeChangeCallbacks) {
EXPECT_TRUE(tree.Unserialize(update1));
const std::vector<std::string>& change_log2 =
- fake_delegate2.attribute_change_log();
+ test_observer2.attribute_change_log();
ASSERT_EQ(11U, change_log2.size());
EXPECT_EQ("name changed from N2 to ", change_log2[0]);
EXPECT_EQ("description changed from D2 to D3", change_log2[1]);
@@ -847,8 +829,6 @@ TEST(AXTreeTest, AttributeChangeCallbacks) {
EXPECT_EQ("scrollXMin changed from 2 to 0", change_log2[8]);
EXPECT_EQ("scrollX changed from 6 to 7", change_log2[9]);
EXPECT_EQ("scrollXMax changed from 0 to 10", change_log2[10]);
-
- tree.SetDelegate(nullptr);
}
TEST(AXTreeTest, IntListChangeCallbacks) {
@@ -872,8 +852,7 @@ TEST(AXTreeTest, IntListChangeCallbacks) {
ax::mojom::IntListAttribute::kRadioGroupIds, two);
AXTree tree(initial_state);
- FakeAXTreeDelegate fake_delegate;
- tree.SetDelegate(&fake_delegate);
+ TestAXTreeObserver test_observer(&tree);
// Change existing attributes.
AXTreeUpdate update0;
@@ -887,13 +866,12 @@ TEST(AXTreeTest, IntListChangeCallbacks) {
EXPECT_TRUE(tree.Unserialize(update0));
const std::vector<std::string>& change_log =
- fake_delegate.attribute_change_log();
+ test_observer.attribute_change_log();
ASSERT_EQ(2U, change_log.size());
EXPECT_EQ("controlsIds changed from 1 to 2,2", change_log[0]);
EXPECT_EQ("radioGroupIds changed from 2,2 to 3", change_log[1]);
- FakeAXTreeDelegate fake_delegate2;
- tree.SetDelegate(&fake_delegate2);
+ TestAXTreeObserver test_observer2(&tree);
// Add and remove attributes.
AXTreeUpdate update1;
@@ -907,13 +885,11 @@ TEST(AXTreeTest, IntListChangeCallbacks) {
EXPECT_TRUE(tree.Unserialize(update1));
const std::vector<std::string>& change_log2 =
- fake_delegate2.attribute_change_log();
+ test_observer2.attribute_change_log();
ASSERT_EQ(3U, change_log2.size());
EXPECT_EQ("controlsIds changed from 2,2 to ", change_log2[0]);
EXPECT_EQ("radioGroupIds changed from 3 to 2,2", change_log2[1]);
EXPECT_EQ("flowtoIds changed from to 3", change_log2[2]);
-
- tree.SetDelegate(nullptr);
}
// Create a very simple tree and make sure that we can get the bounds of
@@ -1420,6 +1396,10 @@ TEST(AXTreeTest, SkipIgnoredNodes) {
}
TEST(AXTreeTest, ChildTreeIds) {
+ ui::AXTreeID tree_id_1 = ui::AXTreeID::CreateNewAXTreeID();
+ ui::AXTreeID tree_id_2 = ui::AXTreeID::CreateNewAXTreeID();
+ ui::AXTreeID tree_id_3 = ui::AXTreeID::CreateNewAXTreeID();
+
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(4);
@@ -1429,50 +1409,45 @@ TEST(AXTreeTest, ChildTreeIds) {
initial_state.nodes[0].child_ids.push_back(4);
initial_state.nodes[1].id = 2;
initial_state.nodes[1].AddStringAttribute(
- ax::mojom::StringAttribute::kChildTreeId, "92");
+ ax::mojom::StringAttribute::kChildTreeId, tree_id_2.ToString());
initial_state.nodes[2].id = 3;
initial_state.nodes[2].AddStringAttribute(
- ax::mojom::StringAttribute::kChildTreeId, "93");
+ ax::mojom::StringAttribute::kChildTreeId, tree_id_3.ToString());
initial_state.nodes[3].id = 4;
initial_state.nodes[3].AddStringAttribute(
- ax::mojom::StringAttribute::kChildTreeId, "93");
+ ax::mojom::StringAttribute::kChildTreeId, tree_id_3.ToString());
AXTree tree(initial_state);
- auto child_tree_91_nodes =
- tree.GetNodeIdsForChildTreeId(AXTreeID::FromString("91"));
- EXPECT_EQ(0U, child_tree_91_nodes.size());
+ auto child_tree_1_nodes = tree.GetNodeIdsForChildTreeId(tree_id_1);
+ EXPECT_EQ(0U, child_tree_1_nodes.size());
- auto child_tree_92_nodes =
- tree.GetNodeIdsForChildTreeId(AXTreeID::FromString("92"));
- EXPECT_EQ(1U, child_tree_92_nodes.size());
- EXPECT_TRUE(base::ContainsKey(child_tree_92_nodes, 2));
+ auto child_tree_2_nodes = tree.GetNodeIdsForChildTreeId(tree_id_2);
+ EXPECT_EQ(1U, child_tree_2_nodes.size());
+ EXPECT_TRUE(base::ContainsKey(child_tree_2_nodes, 2));
- auto child_tree_93_nodes =
- tree.GetNodeIdsForChildTreeId(AXTreeID::FromString("93"));
- EXPECT_EQ(2U, child_tree_93_nodes.size());
- EXPECT_TRUE(base::ContainsKey(child_tree_93_nodes, 3));
- EXPECT_TRUE(base::ContainsKey(child_tree_93_nodes, 4));
+ auto child_tree_3_nodes = tree.GetNodeIdsForChildTreeId(tree_id_3);
+ EXPECT_EQ(2U, child_tree_3_nodes.size());
+ EXPECT_TRUE(base::ContainsKey(child_tree_3_nodes, 3));
+ EXPECT_TRUE(base::ContainsKey(child_tree_3_nodes, 4));
AXTreeUpdate update = initial_state;
update.nodes[2].string_attributes.clear();
update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
- "92");
+ tree_id_2.ToString());
update.nodes[3].string_attributes.clear();
EXPECT_TRUE(tree.Unserialize(update));
- child_tree_92_nodes =
- tree.GetNodeIdsForChildTreeId(AXTreeID::FromString("92"));
- EXPECT_EQ(2U, child_tree_92_nodes.size());
- EXPECT_TRUE(base::ContainsKey(child_tree_92_nodes, 2));
- EXPECT_TRUE(base::ContainsKey(child_tree_92_nodes, 3));
+ child_tree_2_nodes = tree.GetNodeIdsForChildTreeId(tree_id_2);
+ EXPECT_EQ(2U, child_tree_2_nodes.size());
+ EXPECT_TRUE(base::ContainsKey(child_tree_2_nodes, 2));
+ EXPECT_TRUE(base::ContainsKey(child_tree_2_nodes, 3));
- child_tree_93_nodes =
- tree.GetNodeIdsForChildTreeId(AXTreeID::FromString("93"));
- EXPECT_EQ(0U, child_tree_93_nodes.size());
+ child_tree_3_nodes = tree.GetNodeIdsForChildTreeId(tree_id_3);
+ EXPECT_EQ(0U, child_tree_3_nodes.size());
}
-// Tests PosInSet and SetSize int attributes work if assigned.
+// Tests GetPosInSet and GetSetSize return the assigned int attribute values.
TEST(AXTreeTest, TestSetSizePosInSetAssigned) {
AXTreeUpdate tree_update;
tree_update.root_id = 1;
@@ -1505,7 +1480,7 @@ TEST(AXTreeTest, TestSetSizePosInSetAssigned) {
EXPECT_EQ(item3->GetSetSize(), 12);
}
-// Tests that PosInSet and SetSize can be calculated if not assigned.
+// Tests that pos_in_set and set_size can be calculated if not assigned.
TEST(AXTreeTest, TestSetSizePosInSetUnassigned) {
AXTreeUpdate tree_update;
tree_update.root_id = 1;
@@ -1532,7 +1507,8 @@ TEST(AXTreeTest, TestSetSizePosInSetUnassigned) {
EXPECT_EQ(item3->GetSetSize(), 3);
}
-// Tests PosInSet unassigned, while SetSize assigned in container.
+// Tests pos_in_set can be calculated if unassigned, and set_size can be
+// assigned on the outerlying ordered set.
TEST(AXTreeTest, TestSetSizeAssignedInContainer) {
AXTreeUpdate tree_update;
tree_update.root_id = 1;
@@ -1549,7 +1525,7 @@ TEST(AXTreeTest, TestSetSizeAssignedInContainer) {
tree_update.nodes[3].role = ax::mojom::Role::kListItem;
AXTree tree(tree_update);
- // Items should inherit SetSize from container if not specified.
+ // Items should inherit set_size from ordered set if not specified.
AXNode* item1 = tree.GetFromId(2);
EXPECT_EQ(item1->GetSetSize(), 7);
AXNode* item2 = tree.GetFromId(3);
@@ -1558,60 +1534,48 @@ TEST(AXTreeTest, TestSetSizeAssignedInContainer) {
EXPECT_EQ(item3->GetSetSize(), 7);
}
-// Tests PosInSet and SetSize on a list containing various roles.
-// Roles for items and associated container should match up.
+// Tests GetPosInSet and GetSetSize on a list containing various roles.
+// Roles for items and associated ordered set should match up.
TEST(AXTreeTest, TestSetSizePosInSetDiverseList) {
AXTreeUpdate tree_update;
tree_update.root_id = 1;
- tree_update.nodes.resize(9);
+ 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, 7, 8, 9};
+ tree_update.nodes[0].role = ax::mojom::Role::kMenu;
+ 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 3
+ tree_update.nodes[1].role = ax::mojom::Role::kMenuItem; // 1 of 4
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].role = ax::mojom::Role::kMenuItem; // 0 of 0
+ tree_update.nodes[2].role = ax::mojom::Role::kMenuItemCheckBox; // 2 of 4
tree_update.nodes[3].id = 4;
- tree_update.nodes[3].role = ax::mojom::Role::kListItem; // 2 of 3
+ tree_update.nodes[3].role = ax::mojom::Role::kMenuItemRadio; // 3 of 4
tree_update.nodes[4].id = 5;
- tree_update.nodes[4].role = ax::mojom::Role::kMenuItem; // 0 of 0
+ tree_update.nodes[4].role = ax::mojom::Role::kMenuItem; // 4 of 4
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
+ tree_update.nodes[5].role = ax::mojom::Role::kTab; // 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);
+ // kMenu is allowed to contain: kMenuItem, kMenuItemCheckbox,
+ // and kMenuItemRadio. For PosInSet and SetSize purposes, these items
+ // are treated as the same role.
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 1);
+ EXPECT_EQ(item1->GetSetSize(), 4);
+ AXNode* checkbox = tree.GetFromId(3);
+ EXPECT_EQ(checkbox->GetPosInSet(), 2);
+ EXPECT_EQ(checkbox->GetSetSize(), 4);
+ AXNode* radio = tree.GetFromId(4);
+ EXPECT_EQ(radio->GetPosInSet(), 3);
+ EXPECT_EQ(radio->GetSetSize(), 4);
+ AXNode* item3 = tree.GetFromId(5);
+ EXPECT_EQ(item3->GetPosInSet(), 4);
+ EXPECT_EQ(item3->GetSetSize(), 4);
+ AXNode* image = tree.GetFromId(6);
EXPECT_EQ(image->GetPosInSet(), 0);
EXPECT_EQ(image->GetSetSize(), 0);
}
-// Tests PosInSet and SetSize on a nested list.
+// Tests GetPosInSet and GetSetSize on a nested list.
TEST(AXTreeTest, TestSetSizePosInSetNestedList) {
AXTreeUpdate tree_update;
tree_update.root_id = 1;
@@ -1641,12 +1605,6 @@ TEST(AXTreeTest, TestSetSizePosInSetNestedList) {
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);
@@ -1659,8 +1617,8 @@ TEST(AXTreeTest, TestSetSizePosInSetNestedList) {
EXPECT_EQ(outer_item3->GetSetSize(), 3);
}
-// Tests PosInSet can be calculated if one item specifies PosInSet, but others
-// are missing.
+// Tests pos_in_set can be calculated if one item specifies pos_in_set, but
+// other assignments are missing.
TEST(AXTreeTest, TestPosInSetMissing) {
AXTreeUpdate tree_update;
tree_update.root_id = 1;
@@ -1691,7 +1649,7 @@ TEST(AXTreeTest, TestPosInSetMissing) {
EXPECT_EQ(item3->GetSetSize(), 20);
}
-// A more difficult test that invovles missing PosInSet and SetSize values.
+// A more difficult test that invovles missing pos_in_set and set_size values.
TEST(AXTreeTest, TestSetSizePosInSetMissingDifficult) {
AXTreeUpdate tree_update;
tree_update.root_id = 1;
@@ -1732,7 +1690,7 @@ TEST(AXTreeTest, TestSetSizePosInSetMissingDifficult) {
EXPECT_EQ(item5->GetSetSize(), 11);
}
-// Tests that code overwrites decreasing SetSize assignments to largest of
+// Tests that code overwrites decreasing set_size assignments to largest of
// assigned values.
TEST(AXTreeTest, TestSetSizeDecreasing) {
AXTreeUpdate tree_update;
@@ -1762,7 +1720,7 @@ TEST(AXTreeTest, TestSetSizeDecreasing) {
EXPECT_EQ(item3->GetSetSize(), 5);
}
-// Tests that code overwrites decreasing PosInSet values.
+// Tests that code overwrites decreasing pos_in_set values.
TEST(AXTreeTest, TestPosInSetDecreasing) {
AXTreeUpdate tree_update;
tree_update.root_id = 1;
@@ -1791,7 +1749,7 @@ TEST(AXTreeTest, TestPosInSetDecreasing) {
EXPECT_EQ(item3->GetSetSize(), 8);
}
-// Tests that code overwrites duplicate PosInSet values. Note this case is
+// Tests that code overwrites duplicate pos_in_set values. Note this case is
// tricky; an update to the second element causes an update to the third
// element.
TEST(AXTreeTest, TestPosInSetDuplicates) {
@@ -1823,7 +1781,7 @@ TEST(AXTreeTest, TestPosInSetDuplicates) {
EXPECT_EQ(item3->GetSetSize(), 8);
}
-// Tests PosInSet and SetSize when some list items are nested in a generic
+// Tests GetPosInSet and GetSetSize when some list items are nested in a generic
// container.
TEST(AXTreeTest, TestSetSizePosInSetNestedContainer) {
AXTreeUpdate tree_update;
@@ -1868,4 +1826,370 @@ TEST(AXTreeTest, TestSetSizePosInSetNestedContainer) {
EXPECT_EQ(item4->GetSetSize(), 4);
}
+// Tests GetSetSize and GetPosInSet are correct, even when list items change.
+// This test is directed at the caching functionality of pos_in_set and
+// set_size. Tests that previously calculated values are not used after
+// tree is updated.
+TEST(AXTreeTest, TestSetSizePosInSetDeleteItem) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(4);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kList;
+ initial_state.nodes[0].child_ids = {2, 3, 4};
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kListItem; // 1 of 3
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kListItem; // 2 of 3
+ initial_state.nodes[3].id = 4;
+ initial_state.nodes[3].role = ax::mojom::Role::kListItem; // 3 of 3
+ AXTree tree(initial_state);
+
+ 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);
+
+ // TreeUpdates only need to describe what changed in tree.
+ AXTreeUpdate update = initial_state;
+ update.nodes.resize(1);
+ update.nodes[0].child_ids = {2, 4}; // Delete item 2 of 3 from list.
+ EXPECT_TRUE(tree.Unserialize(update));
+
+ AXNode* new_item1 = tree.GetFromId(2);
+ EXPECT_EQ(new_item1->GetPosInSet(), 1);
+ EXPECT_EQ(new_item1->GetSetSize(), 2);
+ AXNode* new_item2 = tree.GetFromId(4);
+ EXPECT_EQ(new_item2->GetPosInSet(), 2);
+ EXPECT_EQ(new_item2->GetSetSize(), 2);
+}
+
+// Tests GetSetSize and GetPosInSet are correct, even when list items change.
+// This test adds an item to the front of a list, which invalidates previously
+// calculated pos_in_set and set_size values. Tests that old values are not
+// used after tree is updated.
+TEST(AXTreeTest, TestSetSizePosInSetAddItem) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(4);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kList;
+ initial_state.nodes[0].child_ids = {2, 3, 4};
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kListItem; // 1 of 3
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kListItem; // 2 of 3
+ initial_state.nodes[3].id = 4;
+ initial_state.nodes[3].role = ax::mojom::Role::kListItem; // 3 of 3
+ AXTree tree(initial_state);
+
+ 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);
+
+ // Insert item at beginning of list
+ AXTreeUpdate update = initial_state;
+ update.nodes.resize(2);
+ update.nodes[0].id = 1;
+ update.nodes[0].child_ids = {5, 2, 3, 4};
+ update.nodes[1].id = 5;
+ update.nodes[1].role = ax::mojom::Role::kListItem;
+ EXPECT_TRUE(tree.Unserialize(update));
+
+ AXNode* new_item1 = tree.GetFromId(5);
+ EXPECT_EQ(new_item1->GetPosInSet(), 1);
+ EXPECT_EQ(new_item1->GetSetSize(), 4);
+ AXNode* new_item2 = tree.GetFromId(2);
+ EXPECT_EQ(new_item2->GetPosInSet(), 2);
+ EXPECT_EQ(new_item2->GetSetSize(), 4);
+ AXNode* new_item3 = tree.GetFromId(3);
+ EXPECT_EQ(new_item3->GetPosInSet(), 3);
+ EXPECT_EQ(new_item3->GetSetSize(), 4);
+ AXNode* new_item4 = tree.GetFromId(4);
+ EXPECT_EQ(new_item4->GetPosInSet(), 4);
+ EXPECT_EQ(new_item4->GetSetSize(), 4);
+}
+
+// Tests that the outerlying ordered set reports a set_size. Ordered sets
+// should not report a pos_in_set value other than 0, since they are not
+// considered to be items within a set (even when nested).
+TEST(AXTreeTest, TestOrderedSetReportsSetSize) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(12);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList; // set_size = 3
+ tree_update.nodes[0].child_ids = {2, 3, 4, 7, 8, 9, 12};
+ 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::kListItem; // 2 of 3
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kList; // set_size = 2
+ tree_update.nodes[3].child_ids = {5, 6};
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].role = ax::mojom::Role::kListItem; // 1 of 2
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].role = ax::mojom::Role::kListItem; // 2 of 2
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].role = ax::mojom::Role::kListItem; // 3 of 3
+ tree_update.nodes[7].id = 8;
+ tree_update.nodes[7].role = ax::mojom::Role::kList; // set_size = 0
+ tree_update.nodes[8].id = 9;
+ tree_update.nodes[8].role =
+ ax::mojom::Role::kList; // set_size = 1 because only 1 item whose role
+ // matches
+ tree_update.nodes[8].child_ids = {10, 11};
+ tree_update.nodes[9].id = 10;
+ tree_update.nodes[9].role = ax::mojom::Role::kArticle;
+ tree_update.nodes[10].id = 11;
+ tree_update.nodes[10].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[11].id = 12;
+ tree_update.nodes[11].role = ax::mojom::Role::kList;
+ tree_update.nodes[11].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 5);
+ AXTree tree(tree_update);
+
+ AXNode* outer_list = tree.GetFromId(1);
+ EXPECT_EQ(outer_list->GetPosInSet(), 0); // Ordered sets have pos of 0
+ EXPECT_EQ(outer_list->GetSetSize(), 3);
+ AXNode* outer_list_item1 = tree.GetFromId(2);
+ EXPECT_EQ(outer_list_item1->GetPosInSet(), 1);
+ EXPECT_EQ(outer_list_item1->GetSetSize(), 3);
+ AXNode* outer_list_item2 = tree.GetFromId(3);
+ EXPECT_EQ(outer_list_item2->GetPosInSet(), 2);
+ EXPECT_EQ(outer_list_item2->GetSetSize(), 3);
+ AXNode* outer_list_item3 = tree.GetFromId(7);
+ EXPECT_EQ(outer_list_item3->GetPosInSet(), 3);
+ EXPECT_EQ(outer_list_item3->GetSetSize(), 3);
+
+ AXNode* inner_list1 = tree.GetFromId(4);
+ EXPECT_EQ(inner_list1->GetPosInSet(),
+ 0); // Ordered sets have pos of 0, even when nested
+ EXPECT_EQ(inner_list1->GetSetSize(), 2);
+ AXNode* inner_list1_item1 = tree.GetFromId(5);
+ EXPECT_EQ(inner_list1_item1->GetPosInSet(), 1);
+ EXPECT_EQ(inner_list1_item1->GetSetSize(), 2);
+ AXNode* inner_list1_item2 = tree.GetFromId(6);
+ EXPECT_EQ(inner_list1_item2->GetPosInSet(), 2);
+ EXPECT_EQ(inner_list1_item2->GetSetSize(), 2);
+
+ AXNode* inner_list2 = tree.GetFromId(8); // Empty list
+ EXPECT_EQ(inner_list2->GetPosInSet(), 0);
+ EXPECT_EQ(inner_list2->GetSetSize(), 0);
+
+ AXNode* inner_list3 = tree.GetFromId(9);
+ EXPECT_EQ(inner_list3->GetPosInSet(), 0);
+ EXPECT_EQ(inner_list3->GetSetSize(), 1); // Only 1 item whose role matches
+ AXNode* inner_list3_article1 = tree.GetFromId(10);
+ EXPECT_EQ(inner_list3_article1->GetPosInSet(), 0);
+ EXPECT_EQ(inner_list3_article1->GetSetSize(), 0);
+ AXNode* inner_list3_item1 = tree.GetFromId(11);
+ EXPECT_EQ(inner_list3_item1->GetPosInSet(), 1);
+ EXPECT_EQ(inner_list3_item1->GetSetSize(), 1);
+
+ AXNode* inner_list4 = tree.GetFromId(12);
+ EXPECT_EQ(inner_list4->GetPosInSet(), 0);
+ // Even though list is empty, kSetSize attribute was set, so it takes
+ // precedence
+ EXPECT_EQ(inner_list4->GetSetSize(), 5);
+}
+
+// Tests GetPosInSet and GetSetSize code on invalid input.
+TEST(AXTreeTest, TestSetSizePosInSetInvalid) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(3);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kListItem; // 0 of 0
+ tree_update.nodes[0].child_ids = {2, 3};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
+ 4); // 0 of 0
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem;
+ AXTree tree(tree_update);
+
+ AXNode* item1 = tree.GetFromId(1);
+ EXPECT_EQ(item1->GetPosInSet(), 0);
+ EXPECT_EQ(item1->GetSetSize(), 0);
+ AXNode* item2 = tree.GetFromId(2);
+ EXPECT_EQ(item2->GetPosInSet(), 0);
+ EXPECT_EQ(item2->GetSetSize(), 0);
+ AXNode* item3 = tree.GetFromId(3);
+ EXPECT_EQ(item3->GetPosInSet(), 0);
+ EXPECT_EQ(item3->GetSetSize(), 0);
+}
+
+// Tests GetPosInSet and GetSetSize code on kRadioButtons. Radio buttons
+// behave differently than other item-like elements; most notably, they do not
+// need to be contained within an ordered set to report a PosInSet or SetSize.
+TEST(AXTreeTest, TestSetSizePosInSetRadioButtons) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(13);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].child_ids = {2, 3, 4, 10, 13};
+
+ // Radio buttons are not required to be contained within an ordered set.
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kRadioButton; // 1 of 5
+ tree_update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "sports");
+ tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 1);
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kRadioButton; // 2 of 5
+ tree_update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "books");
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 2);
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 5);
+
+ // Radio group with nested generic container.
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kRadioGroup; // setsize = 4
+ tree_update.nodes[3].child_ids = {5, 6, 7};
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].role = ax::mojom::Role::kRadioButton;
+ tree_update.nodes[4].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "recipes"); // 1 of 4
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].role = ax::mojom::Role::kRadioButton;
+ tree_update.nodes[5].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "recipes"); // 2 of 4
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].role = ax::mojom::Role::kGenericContainer;
+ tree_update.nodes[6].child_ids = {8, 9};
+ tree_update.nodes[7].id = 8;
+ tree_update.nodes[7].role = ax::mojom::Role::kRadioButton;
+ tree_update.nodes[7].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "recipes"); // 3 of 4
+ tree_update.nodes[8].id = 9;
+ tree_update.nodes[8].role = ax::mojom::Role::kRadioButton;
+ tree_update.nodes[8].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "recipes"); // 4 of 4
+
+ // Radio buttons are allowed to be contained within forms.
+ tree_update.nodes[9].id = 10;
+ tree_update.nodes[9].role = ax::mojom::Role::kForm;
+ tree_update.nodes[9].child_ids = {11, 12};
+ tree_update.nodes[10].id = 11;
+ tree_update.nodes[10].role = ax::mojom::Role::kRadioButton;
+ tree_update.nodes[10].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "cities"); // 1 of 2
+ tree_update.nodes[11].id = 12;
+ tree_update.nodes[11].role = ax::mojom::Role::kRadioButton;
+ tree_update.nodes[11].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "cities"); // 2 of 2
+ tree_update.nodes[12].id = 13;
+ tree_update.nodes[12].role = ax::mojom::Role::kRadioButton; // 4 of 5
+ tree_update.nodes[12].AddStringAttribute(ax::mojom::StringAttribute::kName,
+ "sports");
+ tree_update.nodes[12].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 4);
+
+ AXTree tree(tree_update);
+
+ AXNode* sports_button1 = tree.GetFromId(2);
+ EXPECT_EQ(sports_button1->GetPosInSet(), 1);
+ EXPECT_EQ(sports_button1->GetSetSize(), 5);
+ AXNode* books_button = tree.GetFromId(3);
+ EXPECT_EQ(books_button->GetPosInSet(), 2);
+ EXPECT_EQ(books_button->GetSetSize(), 5);
+
+ AXNode* radiogroup1 = tree.GetFromId(4);
+ EXPECT_EQ(radiogroup1->GetPosInSet(), 0);
+ EXPECT_EQ(radiogroup1->GetSetSize(), 4);
+ AXNode* recipes_button1 = tree.GetFromId(5);
+ EXPECT_EQ(recipes_button1->GetPosInSet(), 1);
+ EXPECT_EQ(recipes_button1->GetSetSize(), 4);
+ AXNode* recipes_button2 = tree.GetFromId(6);
+ EXPECT_EQ(recipes_button2->GetPosInSet(), 2);
+ EXPECT_EQ(recipes_button2->GetSetSize(), 4);
+
+ AXNode* generic_container = tree.GetFromId(7);
+ EXPECT_EQ(generic_container->GetPosInSet(), 0);
+ EXPECT_EQ(generic_container->GetSetSize(), 0);
+ AXNode* recipes_button3 = tree.GetFromId(8);
+ EXPECT_EQ(recipes_button3->GetPosInSet(), 3);
+ EXPECT_EQ(recipes_button3->GetSetSize(), 4);
+ AXNode* recipes_button4 = tree.GetFromId(9);
+ EXPECT_EQ(recipes_button4->GetPosInSet(), 4);
+ EXPECT_EQ(recipes_button4->GetSetSize(), 4);
+
+ // Elements with role kForm shouldn't report posinset or setsize
+ AXNode* form = tree.GetFromId(10);
+ EXPECT_EQ(form->GetPosInSet(), 0);
+ EXPECT_EQ(form->GetSetSize(), 0);
+ AXNode* cities_button1 = tree.GetFromId(11);
+ EXPECT_EQ(cities_button1->GetPosInSet(), 1);
+ EXPECT_EQ(cities_button1->GetSetSize(), 2);
+ AXNode* cities_button2 = tree.GetFromId(12);
+ EXPECT_EQ(cities_button2->GetPosInSet(), 2);
+ EXPECT_EQ(cities_button2->GetSetSize(), 2);
+
+ AXNode* sports_button2 = tree.GetFromId(13);
+ EXPECT_EQ(sports_button2->GetPosInSet(), 4);
+ EXPECT_EQ(sports_button2->GetSetSize(), 5);
+}
+
+// Tests GetPosInSet and GetSetSize on a list that includes radio buttons.
+// Note that radio buttons do not contribute to the SetSize of the outerlying
+// list.
+TEST(AXTreeTest, TestSetSizePosInSetRadioButtonsInList) {
+ 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; // set_size = 2, since only contains 2 ListItems
+ 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::kRadioButton; // 1 of 3
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem; // 1 of 2
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kRadioButton; // 2 of 3
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].role = ax::mojom::Role::kListItem; // 2 of 2
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].role = ax::mojom::Role::kRadioButton; // 3 of 3
+ AXTree tree(tree_update);
+
+ AXNode* list = tree.GetFromId(1);
+ EXPECT_EQ(list->GetPosInSet(), 0);
+ EXPECT_EQ(list->GetSetSize(), 2);
+
+ AXNode* radiobutton1 = tree.GetFromId(2);
+ EXPECT_EQ(radiobutton1->GetPosInSet(), 1);
+ EXPECT_EQ(radiobutton1->GetSetSize(), 3);
+ AXNode* item1 = tree.GetFromId(3);
+ EXPECT_EQ(item1->GetPosInSet(), 1);
+ EXPECT_EQ(item1->GetSetSize(), 2);
+ AXNode* radiobutton2 = tree.GetFromId(4);
+ EXPECT_EQ(radiobutton2->GetPosInSet(), 2);
+ EXPECT_EQ(radiobutton2->GetSetSize(), 3);
+ AXNode* item2 = tree.GetFromId(5);
+ EXPECT_EQ(item2->GetPosInSet(), 2);
+ EXPECT_EQ(item2->GetSetSize(), 2);
+ AXNode* radiobutton3 = tree.GetFromId(6);
+ EXPECT_EQ(radiobutton3->GetPosInSet(), 3);
+ EXPECT_EQ(radiobutton3->GetSetSize(), 3);
+
+ // Ensure that the setsize of list was not modified after calling GetPosInSet
+ // and GetSetSize on kRadioButtons.
+ EXPECT_EQ(list->GetPosInSet(), 0);
+ EXPECT_EQ(list->GetSetSize(), 2);
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_update.h b/chromium/ui/accessibility/ax_tree_update.h
index a2d8e28c070..4481fd761fe 100644
--- a/chromium/ui/accessibility/ax_tree_update.h
+++ b/chromium/ui/accessibility/ax_tree_update.h
@@ -9,9 +9,9 @@
#include <stdint.h>
#include <string>
+#include <unordered_map>
#include <vector>
-#include "base/containers/hash_tables.h"
#include "base/strings/string_number_conversions.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_data.h"
@@ -103,7 +103,7 @@ std::string AXTreeUpdateBase<AXNodeData, AXTreeData>::ToString() const {
// to the rest of the tree for context, so we have to try to show the
// relative indentation of child nodes in this update relative to their
// parents.
- base::hash_map<int32_t, int> id_to_indentation;
+ std::unordered_map<int32_t, int> id_to_indentation;
for (size_t i = 0; i < nodes.size(); ++i) {
int indent = id_to_indentation[nodes[i].id];
result += std::string(2 * indent, ' ');
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 4327852e622..73636791de4 100644
--- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_te.xtb
+++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_te.xtb
@@ -18,13 +18,13 @@
<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">చిత్రం ప్రత్యామ్నాయ వచన వ్యూయర్</translation>
-<translation id="381767806621926835">"longdesc" లేదా "aria-describedat" లక్షణం ఉన్న ఏదైనా అంశం యొక్క సుదీర్ఘ వివరణను యాక్సెస్ చేయడానికి దానిపై కుడి క్లిక్ చేయండి.</translation>
+<translation id="381767806621926835">"longdesc" లేదా "aria-describedat" ఫీచర్ ఉన్న ఏదైనా అంశం యొక్క సుదీర్ఘ వివరణను యాక్సెస్ చేయడానికి దానిపై కుడి క్లిక్ చేయండి.</translation>
<translation id="4023902424053835668">బాణం కీలను ఉపయోగించి వెబ్ పేజీల వచనాన్ని బ్రౌజ్ చేయండి.</translation>
<translation id="4388820049312272371">కర్సర్ స్థానాన్ని శీఘ్ర ఫ్లాష్‌తో హైలైట్ చేయండి.</translation>
<translation id="4394049700291259645">ఆపివెయ్యి</translation>
@@ -65,5 +65,5 @@
<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/mojom/ax_action_data_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_action_data_mojom_traits_unittest.cc
index 68603e3c5b5..e8f9364a1f8 100644
--- a/chromium/ui/accessibility/mojom/ax_action_data_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_action_data_mojom_traits_unittest.cc
@@ -17,7 +17,8 @@ using mojo::test::SerializeAndDeserialize;
TEST(AXActionDataMojomTraitsTest, RoundTrip) {
ui::AXActionData input;
input.action = ax::mojom::Action::kBlur;
- input.target_tree_id = ui::AXTreeID::FromString("1");
+ input.target_tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ EXPECT_EQ(32U, input.target_tree_id.ToString().size());
input.source_extension_id = "extension_id";
input.target_node_id = 2;
input.request_id = 3;
@@ -37,7 +38,8 @@ TEST(AXActionDataMojomTraitsTest, RoundTrip) {
SerializeAndDeserialize<ax::mojom::AXActionData>(&input, &output));
EXPECT_EQ(output.action, ax::mojom::Action::kBlur);
- EXPECT_EQ(output.target_tree_id.ToString(), "1");
+ EXPECT_EQ(output.target_tree_id, input.target_tree_id);
+ EXPECT_EQ(output.target_tree_id.ToString(), input.target_tree_id.ToString());
EXPECT_EQ(output.source_extension_id, "extension_id");
EXPECT_EQ(output.target_node_id, 2);
EXPECT_EQ(output.request_id, 3);
diff --git a/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits_unittest.cc
index d64ff2c8fe7..fa3cb0eb12a 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits_unittest.cc
@@ -11,10 +11,14 @@
using mojo::test::SerializeAndDeserialize;
TEST(AXTreeDataMojomTraitsTest, TestSerializeAndDeserializeAXTreeData) {
+ ui::AXTreeID tree_id_1 = ui::AXTreeID::CreateNewAXTreeID();
+ ui::AXTreeID tree_id_2 = ui::AXTreeID::CreateNewAXTreeID();
+ ui::AXTreeID tree_id_3 = ui::AXTreeID::CreateNewAXTreeID();
+
ui::AXTreeData input, output;
- input.tree_id = ui::AXTreeID::FromString("1");
- input.parent_tree_id = ui::AXTreeID::FromString("2");
- input.focused_tree_id = ui::AXTreeID::FromString("3");
+ input.tree_id = tree_id_1;
+ input.parent_tree_id = tree_id_2;
+ input.focused_tree_id = tree_id_3;
input.doctype = "4";
input.loaded = true;
input.loading_progress = 5;
@@ -31,9 +35,9 @@ TEST(AXTreeDataMojomTraitsTest, TestSerializeAndDeserializeAXTreeData) {
EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeData>(&input, &output));
- EXPECT_EQ("1", output.tree_id.ToString());
- EXPECT_EQ("2", output.parent_tree_id.ToString());
- EXPECT_EQ("3", output.focused_tree_id.ToString());
+ EXPECT_EQ(tree_id_1, output.tree_id);
+ EXPECT_EQ(tree_id_2, output.parent_tree_id);
+ EXPECT_EQ(tree_id_3, output.focused_tree_id);
EXPECT_EQ("4", output.doctype);
EXPECT_EQ(true, output.loaded);
EXPECT_EQ(5, output.loading_progress);
diff --git a/chromium/ui/accessibility/mojom/ax_tree_id.mojom b/chromium/ui/accessibility/mojom/ax_tree_id.mojom
index 6cc327b402d..0f3c79437e2 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_id.mojom
+++ b/chromium/ui/accessibility/mojom/ax_tree_id.mojom
@@ -4,7 +4,13 @@
module ax.mojom;
-struct AXTreeID {
- // Eventually this may become a base::UnguessableToken.
- string id;
+import "ui/accessibility/ax_enums.mojom";
+import "mojo/public/mojom/base/unguessable_token.mojom";
+
+union AXTreeID {
+ // Placeholder for an unknown AXTreeID. The value of this field is not used.
+ uint8 unknown;
+
+ // Any AXTreeID that's not unknown must be an UnguessableToken.
+ mojo_base.mojom.UnguessableToken token;
};
diff --git a/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.cc
index 949b7db86e4..d801177eb69 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.cc
+++ b/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.cc
@@ -7,12 +7,22 @@
namespace mojo {
// static
-bool StructTraits<ax::mojom::AXTreeIDDataView, ui::AXTreeID>::Read(
+bool UnionTraits<ax::mojom::AXTreeIDDataView, ui::AXTreeID>::Read(
ax::mojom::AXTreeIDDataView data,
ui::AXTreeID* out) {
- if (!data.ReadId(&out->id_))
- return false;
- return true;
+ switch (data.tag()) {
+ case ax::mojom::AXTreeIDDataView::Tag::UNKNOWN:
+ out->type_ = ax::mojom::AXTreeIDType::kUnknown;
+ return true;
+ case ax::mojom::AXTreeIDDataView::Tag::TOKEN:
+ out->type_ = ax::mojom::AXTreeIDType::kToken;
+ if (!data.ReadToken(&out->token_))
+ return false;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
}
} // namespace mojo
diff --git a/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.h
index df481aad53a..13fc696546a 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.h
+++ b/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits.h
@@ -5,14 +5,27 @@
#ifndef UI_ACCESSIBILITY_MOJOM_AX_TREE_ID_MOJOM_TRAITS_H_
#define UI_ACCESSIBILITY_MOJOM_AX_TREE_ID_MOJOM_TRAITS_H_
+#include "mojo/public/cpp/base/unguessable_token_mojom_traits.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/mojom/ax_tree_id.mojom-shared.h"
namespace mojo {
template <>
-struct StructTraits<ax::mojom::AXTreeIDDataView, ui::AXTreeID> {
- static const std::string& id(const ui::AXTreeID& p) { return p.ToString(); }
+struct UnionTraits<ax::mojom::AXTreeIDDataView, ui::AXTreeID> {
+ static ax::mojom::AXTreeIDDataView::Tag GetTag(const ui::AXTreeID& p) {
+ switch (p.type()) {
+ case ax::mojom::AXTreeIDType::kUnknown:
+ return ax::mojom::AXTreeIDDataView::Tag::UNKNOWN;
+ case ax::mojom::AXTreeIDType::kToken:
+ return ax::mojom::AXTreeIDDataView::Tag::TOKEN;
+ }
+ }
+ static uint8_t unknown(const ui::AXTreeID& p) { return 0; }
+ static const base::UnguessableToken token(const ui::AXTreeID& p) {
+ DCHECK_EQ(p.type(), ax::mojom::AXTreeIDType::kToken);
+ return *p.token();
+ }
static bool Read(ax::mojom::AXTreeIDDataView data, ui::AXTreeID* out);
};
diff --git a/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits_unittest.cc
index 3f0f4837caf..fadf6cc54c3 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits_unittest.cc
@@ -11,8 +11,25 @@
using mojo::test::SerializeAndDeserialize;
TEST(AXTreeIDMojomTraitsTest, TestSerializeAndDeserializeAXTreeID) {
- ui::AXTreeID input = ui::AXTreeID::FromString("abc");
- ui::AXTreeID output;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeID>(&input, &output));
- EXPECT_EQ("abc", output.ToString());
+ ui::AXTreeID empty_input = ui::AXTreeID();
+ ui::AXTreeID empty_output;
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeID>(&empty_input,
+ &empty_output));
+ EXPECT_EQ(empty_input, empty_output);
+ EXPECT_EQ("", empty_output.ToString());
+
+ ui::AXTreeID unknown_input = ui::AXTreeIDUnknown();
+ ui::AXTreeID unknown_output;
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeID>(&unknown_input,
+ &unknown_output));
+ EXPECT_EQ(unknown_input, unknown_output);
+ EXPECT_EQ("", unknown_output.ToString());
+
+ ui::AXTreeID token_input = ui::AXTreeID::CreateNewAXTreeID();
+ ui::AXTreeID token_output;
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeID>(&token_input,
+ &token_output));
+ EXPECT_EQ(token_input, token_output);
+ // It should be a 32-char hex string.
+ EXPECT_EQ(32U, token_output.ToString().size());
}
diff --git a/chromium/ui/accessibility/platform/ax_platform_node.cc b/chromium/ui/accessibility/platform/ax_platform_node.cc
index 840944be2f7..ec4f6face44 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node.cc
@@ -4,12 +4,11 @@
#include "ui/accessibility/platform/ax_platform_node.h"
-#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
-#include "ui/base/ui_features.h"
+#include "ui/base/buildflags.h"
namespace ui {
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 154ffcbaf9d..8f30c5b9bfb 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -6,17 +6,23 @@
#include <stdint.h>
+#include <algorithm>
#include <memory>
+#include <set>
#include <string>
#include <utility>
+#include <vector>
#include "base/command_line.h"
+#include "base/no_destructor.h"
+#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_mode_observer.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/ax_text_utils.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/atk_util_auralinux.h"
@@ -258,12 +264,19 @@ static const gchar* AXPlatformNodeAuraLinuxGetDescription(
}
static gint AXPlatformNodeAuraLinuxGetIndexInParent(AtkObject* atk_object) {
- AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
-
- if (!obj)
+ AtkObject* parent = atk_object_get_parent(atk_object);
+ if (!parent)
return -1;
- return obj->GetIndexInParent();
+ int n_children = atk_object_get_n_accessible_children(parent);
+ for (int i = 0; i < n_children; i++) {
+ AtkObject* child = atk_object_ref_accessible_child(parent, i);
+ g_object_unref(child);
+ if (child == atk_object)
+ return i;
+ }
+
+ return -1;
}
static AtkObject* AXPlatformNodeAuraLinuxGetParent(AtkObject* atk_object) {
@@ -297,15 +310,9 @@ static AtkObject* AXPlatformNodeAuraLinuxRefChild(AtkObject* atk_object,
static AtkRelationSet* AXPlatformNodeAuraLinuxRefRelationSet(
AtkObject* atk_object) {
AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
- AtkRelationSet* atk_relation_set =
- ATK_OBJECT_CLASS(kAXPlatformNodeAuraLinuxParentClass)
- ->ref_relation_set(atk_object);
-
if (!obj)
- return atk_relation_set;
-
- obj->GetAtkRelations(atk_relation_set);
- return atk_relation_set;
+ return atk_relation_set_new();
+ return obj->GetAtkRelations();
}
static AtkAttributeSet* AXPlatformNodeAuraLinuxGetAttributes(
@@ -358,15 +365,6 @@ 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,
@@ -744,7 +742,8 @@ static AtkHyperlink* AXPlatformNodeAuraLinuxHypertextGetLink(
return nullptr;
int32_t id = ax_hypertext.hyperlinks[index];
- auto* link = AXPlatformNodeAuraLinux::GetFromUniqueId(id);
+ auto* link = static_cast<AXPlatformNodeAuraLinux*>(
+ AXPlatformNodeBase::GetFromUniqueId(id));
if (!link)
return nullptr;
@@ -969,6 +968,9 @@ static const GInterfaceInfo TextInfo = {
reinterpret_cast<GInterfaceInitFunc>(AXTextInterfaceBaseInit), nullptr,
nullptr};
+//
+// AtkWindow interface.
+//
static void AXWindowInterfaceBaseInit(AtkWindowIface* iface) {}
static const GInterfaceInfo WindowInfo = {
@@ -976,6 +978,197 @@ static const GInterfaceInfo WindowInfo = {
nullptr};
//
+// AtkSelection interface.
+//
+static gboolean AXPlatformNodeAuraLinuxAddSelection(AtkSelection* selection,
+ gint index) {
+ AXPlatformNodeAuraLinux* obj =
+ AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+ if (!obj)
+ return FALSE;
+ if (index < 0 || index >= obj->GetChildCount())
+ return FALSE;
+
+ AXPlatformNodeAuraLinux* child =
+ AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(index));
+ DCHECK(child);
+
+ if (!child->SupportsSelectionWithAtkSelection())
+ return FALSE;
+
+ bool selected = child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected);
+ if (selected)
+ return TRUE;
+
+ AXActionData data;
+ data.action = ax::mojom::Action::kDoDefault;
+ return child->GetDelegate()->AccessibilityPerformAction(data);
+}
+
+static gboolean AXPlatformNodeAuraLinuxClearSelection(AtkSelection* selection) {
+ AXPlatformNodeAuraLinux* obj =
+ AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+ if (!obj)
+ return FALSE;
+
+ int child_count = obj->GetChildCount();
+ bool success = true;
+ for (int i = 0; i < child_count; ++i) {
+ AXPlatformNodeAuraLinux* child =
+ AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+ DCHECK(child);
+
+ if (!child->SupportsSelectionWithAtkSelection())
+ continue;
+
+ bool selected =
+ child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected);
+ if (!selected)
+ continue;
+
+ AXActionData data;
+ data.action = ax::mojom::Action::kDoDefault;
+ success = success && child->GetDelegate()->AccessibilityPerformAction(data);
+ }
+
+ return success;
+}
+
+static AtkObject* AXPlatformNodeAuraLinuxRefSelection(
+ AtkSelection* selection,
+ gint requested_child_index) {
+ AXPlatformNodeAuraLinux* obj =
+ AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+ if (!obj)
+ return nullptr;
+
+ int child_count = obj->GetChildCount();
+ gint selected_count = 0;
+ for (int i = 0; i < child_count; ++i) {
+ AtkObject* child = obj->ChildAtIndex(i);
+ AXPlatformNodeAuraLinux* child_ax_node =
+ AtkObjectToAXPlatformNodeAuraLinux(child);
+ DCHECK(child_ax_node);
+
+ if (child_ax_node->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected)) {
+ if (selected_count == requested_child_index)
+ return static_cast<AtkObject*>(g_object_ref(child));
+ ++selected_count;
+ }
+ }
+
+ return nullptr;
+}
+
+static gint AXPlatformNodeAuraLinuxGetSelectionCount(AtkSelection* selection) {
+ AXPlatformNodeAuraLinux* obj =
+ AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+ if (!obj)
+ return 0;
+
+ int child_count = obj->GetChildCount();
+ gint selected_count = 0;
+ for (int i = 0; i < child_count; ++i) {
+ AXPlatformNodeAuraLinux* child =
+ AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+ DCHECK(child);
+
+ if (child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
+ ++selected_count;
+ }
+
+ return selected_count;
+}
+
+static gboolean AXPlatformNodeAuraLinuxIsChildSelected(AtkSelection* selection,
+ gint index) {
+ AXPlatformNodeAuraLinux* obj =
+ AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+ if (!obj)
+ return FALSE;
+ if (index < 0 || index >= obj->GetChildCount())
+ return FALSE;
+
+ AXPlatformNodeAuraLinux* child =
+ AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(index));
+ DCHECK(child);
+ return child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected);
+}
+
+static gboolean AXPlatformNodeAuraLinuxRemoveSelection(
+ AtkSelection* selection,
+ gint index_into_selected_children) {
+ AXPlatformNodeAuraLinux* obj =
+ AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+
+ int child_count = obj->GetChildCount();
+ for (int i = 0; i < child_count; ++i) {
+ AXPlatformNodeAuraLinux* child =
+ AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+ DCHECK(child);
+
+ bool selected =
+ child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected);
+ if (selected && index_into_selected_children == 0) {
+ if (!child->SupportsSelectionWithAtkSelection())
+ return FALSE;
+
+ AXActionData data;
+ data.action = ax::mojom::Action::kDoDefault;
+ return child->GetDelegate()->AccessibilityPerformAction(data);
+ } else if (selected) {
+ index_into_selected_children--;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean AXPlatformNodeAuraLinuxSelectAllSelection(
+ AtkSelection* selection) {
+ AXPlatformNodeAuraLinux* obj =
+ AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+ if (!obj)
+ return FALSE;
+
+ int child_count = obj->GetChildCount();
+ bool success = true;
+ for (int i = 0; i < child_count; ++i) {
+ AXPlatformNodeAuraLinux* child =
+ AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+ DCHECK(child);
+
+ if (!child->SupportsSelectionWithAtkSelection())
+ continue;
+
+ bool selected =
+ child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected);
+ if (selected)
+ continue;
+
+ AXActionData data;
+ data.action = ax::mojom::Action::kDoDefault;
+ success = success && child->GetDelegate()->AccessibilityPerformAction(data);
+ }
+
+ return success;
+}
+
+static void AXSelectionInterfaceBaseInit(AtkSelectionIface* iface) {
+ iface->add_selection = AXPlatformNodeAuraLinuxAddSelection;
+ iface->clear_selection = AXPlatformNodeAuraLinuxClearSelection;
+ iface->ref_selection = AXPlatformNodeAuraLinuxRefSelection;
+ iface->get_selection_count = AXPlatformNodeAuraLinuxGetSelectionCount;
+ iface->is_child_selected = AXPlatformNodeAuraLinuxIsChildSelected;
+ iface->remove_selection = AXPlatformNodeAuraLinuxRemoveSelection;
+ iface->select_all_selection = AXPlatformNodeAuraLinuxSelectAllSelection;
+}
+
+static const GInterfaceInfo SelectionInfo = {
+ reinterpret_cast<GInterfaceInitFunc>(AXSelectionInterfaceBaseInit), nullptr,
+ nullptr};
+
+//
// The rest of the AXPlatformNodeAtk code, not specific to one
// of the Atk* interfaces.
//
@@ -1068,6 +1261,44 @@ AXPlatformNodeAuraLinux* g_current_selected = nullptr;
// null if if the AtkObject is destroyed.
AtkObject* g_active_top_level_frame = nullptr;
+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 bool IsFrameAncestorOfAtkObject(AtkObject* frame,
+ AtkObject* atk_object) {
+ AtkObject* current_frame = FindAtkObjectParentFrame(atk_object);
+ while (current_frame) {
+ if (current_frame == frame)
+ return true;
+ current_frame =
+ FindAtkObjectParentFrame(atk_object_get_parent(current_frame));
+ }
+ return false;
+}
+
+// Returns a stack of AtkObjects of activated popup menus. Since each popup
+// menu and submenu has its own native window, we want to properly manage the
+// activated state for their containing frames.
+static std::vector<AtkObject*>& GetActiveMenus() {
+ static base::NoDestructor<std::vector<AtkObject*>> active_menus;
+ return *active_menus;
+}
+
+// The currently active frame is g_active_top_level_frame, unless there is an
+// active menu. If there is an active menu the parent frame of the
+// most-recently opened active menu should be the currently active frame.
+AtkObject* ComputeActiveTopLevelFrame() {
+ if (!GetActiveMenus().empty())
+ return FindAtkObjectParentFrame(GetActiveMenus().back());
+ return g_active_top_level_frame;
+}
+
const char* GetUniqueAccessibilityGTypeName(int interface_mask) {
// 37 characters is enough for "AXPlatformNodeAuraLinux%x" with any integer
// value.
@@ -1147,6 +1378,9 @@ int AXPlatformNodeAuraLinux::GetGTypeInterfaceMask() {
if (role == ATK_ROLE_FRAME)
interface_mask |= 1 << ATK_WINDOW_INTERFACE;
+ if (IsContainerWithSelectableChildren(GetData().role))
+ interface_mask |= 1 << ATK_SELECTION_INTERFACE;
+
return interface_mask;
}
@@ -1190,6 +1424,8 @@ GType AXPlatformNodeAuraLinux::GetAccessibilityGType() {
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);
+ if (interface_mask_ & (1 << ATK_SELECTION_INTERFACE))
+ g_type_add_interface_static(type, ATK_TYPE_SELECTION, &SelectionInfo);
return type;
}
@@ -1234,22 +1470,6 @@ AXPlatformNode* AXPlatformNode::FromNativeViewAccessible(
return AtkObjectToAXPlatformNodeAuraLinux(accessible);
}
-using UniqueIdMap = base::hash_map<int32_t, AXPlatformNodeAuraLinux*>;
-// Map from each AXPlatformNode's unique id to its instance.
-base::LazyInstance<UniqueIdMap>::Leaky g_unique_id_map =
- LAZY_INSTANCE_INITIALIZER;
-
-// static
-AXPlatformNodeAuraLinux* AXPlatformNodeAuraLinux::GetFromUniqueId(
- int32_t unique_id) {
- UniqueIdMap* unique_ids = g_unique_id_map.Pointer();
- auto iter = unique_ids->find(unique_id);
- if (iter != unique_ids->end())
- return iter->second;
-
- return nullptr;
-}
-
//
// AXPlatformNodeAuraLinux implementation.
//
@@ -1460,12 +1680,14 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() {
// ax_platform_node_win.cc code does this.
case ax::mojom::Role::kListBoxOption:
return ATK_ROLE_LIST_ITEM;
+ case ax::mojom::Role::kListGrid:
+ return ATK_ROLE_TABLE;
+ case ax::mojom::Role::kListItem:
+ return ATK_ROLE_LIST_ITEM;
case ax::mojom::Role::kListMarker:
// TODO(Accessibility) Having a separate accessible object for the marker
// is inconsistent with other implementations. http://crbug.com/873144.
return kStaticRole;
- case ax::mojom::Role::kListItem:
- return ATK_ROLE_LIST_ITEM;
case ax::mojom::Role::kLog:
return ATK_ROLE_LOG;
case ax::mojom::Role::kMain:
@@ -1646,8 +1868,14 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() {
void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
AXNodeData data = GetData();
- if (atk_object_ == g_active_top_level_frame)
+
+ bool menu_active = !GetActiveMenus().empty();
+ if (!menu_active && atk_object_ == g_active_top_level_frame)
+ atk_state_set_add_state(atk_state_set, ATK_STATE_ACTIVE);
+ if (menu_active &&
+ FindAtkObjectParentFrame(GetActiveMenus().back()) == atk_object_)
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))
@@ -1739,8 +1967,116 @@ void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSED);
}
-void AXPlatformNodeAuraLinux::GetAtkRelations(
- AtkRelationSet* atk_relation_set) {
+struct AtkIntRelation {
+ ax::mojom::IntAttribute attribute;
+ AtkRelationType relation;
+ base::Optional<AtkRelationType> reverse_relation;
+};
+
+static AtkIntRelation kIntRelations[] = {
+ {ax::mojom::IntAttribute::kMemberOfId, ATK_RELATION_MEMBER_OF,
+ base::nullopt},
+#if defined(ATK_226)
+ {ax::mojom::IntAttribute::kDetailsId, ATK_RELATION_DETAILS,
+ ATK_RELATION_DETAILS_FOR},
+ {ax::mojom::IntAttribute::kErrormessageId, ATK_RELATION_ERROR_MESSAGE,
+ ATK_RELATION_ERROR_FOR},
+#endif
+};
+
+struct AtkIntListRelation {
+ ax::mojom::IntListAttribute attribute;
+ AtkRelationType relation;
+ base::Optional<AtkRelationType> reverse_relation;
+};
+
+static AtkIntListRelation kIntListRelations[] = {
+ {ax::mojom::IntListAttribute::kControlsIds, ATK_RELATION_CONTROLLER_FOR,
+ ATK_RELATION_CONTROLLED_BY},
+ {ax::mojom::IntListAttribute::kDescribedbyIds, ATK_RELATION_DESCRIBED_BY,
+ ATK_RELATION_DESCRIPTION_FOR},
+ {ax::mojom::IntListAttribute::kFlowtoIds, ATK_RELATION_FLOWS_TO,
+ ATK_RELATION_FLOWS_FROM},
+ {ax::mojom::IntListAttribute::kLabelledbyIds, ATK_RELATION_LABELLED_BY,
+ ATK_RELATION_LABEL_FOR},
+};
+
+void AXPlatformNodeAuraLinux::AddRelationToSet(AtkRelationSet* relation_set,
+ AtkRelationType relation,
+ int target_id) {
+ // Avoid adding self-referential relations.
+ if (target_id == GetData().id)
+ return;
+
+ // If we were compiled with a newer version of ATK than the runtime version,
+ // it's possible that we might try to add a relation that doesn't exist in
+ // the runtime version of the AtkRelationType enum. This will cause a runtime
+ // error, so return early here if we are about to do that.
+ static base::Optional<int> max_relation_type = base::nullopt;
+ if (!max_relation_type.has_value()) {
+ GEnumClass* enum_class =
+ G_ENUM_CLASS(g_type_class_ref(atk_relation_type_get_type()));
+ max_relation_type = enum_class->maximum;
+ g_type_class_unref(enum_class);
+ }
+ if (relation > max_relation_type.value())
+ return;
+
+ AXPlatformNode* target = GetDelegate()->GetFromNodeID(target_id);
+ if (!target)
+ return;
+ atk_relation_set_add_relation_by_type(relation_set, relation,
+ target->GetNativeViewAccessible());
+}
+
+AtkRelationSet* AXPlatformNodeAuraLinux::GetAtkRelations() {
+ AtkRelationSet* relation_set = atk_relation_set_new();
+
+ // For each possible relation defined by an IntAttribute, we test that
+ // attribute and then look for reverse relations. AddRelationToSet handles
+ // discarding self-referential relations.
+ for (unsigned i = 0; i < G_N_ELEMENTS(kIntRelations); i++) {
+ const AtkIntRelation& relation = kIntRelations[i];
+
+ int target_id;
+ if (GetIntAttribute(relation.attribute, &target_id))
+ AddRelationToSet(relation_set, relation.relation, target_id);
+
+ if (!relation.reverse_relation.has_value())
+ continue;
+
+ std::set<int32_t> target_ids =
+ GetDelegate()->GetReverseRelations(relation.attribute, GetData().id);
+ for (int32_t target_id : target_ids) {
+ AddRelationToSet(relation_set, relation.reverse_relation.value(),
+ target_id);
+ }
+ }
+
+ // Now we do the same for each possible relation defined by an
+ // IntListAttribute. In this case we need to handle each target in the list.
+ for (unsigned i = 0; i < G_N_ELEMENTS(kIntListRelations); i++) {
+ const AtkIntListRelation& relation = kIntListRelations[i];
+
+ std::vector<int32_t> target_ids;
+ if (GetIntListAttribute(relation.attribute, &target_ids)) {
+ for (int32_t target_id : target_ids) {
+ AddRelationToSet(relation_set, relation.relation, target_id);
+ }
+ }
+
+ if (!relation.reverse_relation.has_value())
+ continue;
+
+ std::set<int32_t> reverse_target_ids =
+ GetDelegate()->GetReverseRelations(relation.attribute, GetData().id);
+ for (int32_t target_id : reverse_target_ids) {
+ AddRelationToSet(relation_set, relation.reverse_relation.value(),
+ target_id);
+ }
+ }
+
+ return relation_set;
}
AXPlatformNodeAuraLinux::AXPlatformNodeAuraLinux() = default;
@@ -1753,8 +2089,6 @@ AXPlatformNodeAuraLinux::~AXPlatformNodeAuraLinux() {
}
void AXPlatformNodeAuraLinux::Destroy() {
- g_unique_id_map.Get().erase(GetUniqueId());
-
DestroyAtkObjects();
AXPlatformNodeBase::Destroy();
}
@@ -1762,7 +2096,6 @@ void AXPlatformNodeAuraLinux::Destroy() {
void AXPlatformNodeAuraLinux::Init(AXPlatformNodeDelegate* delegate) {
// Initialize ATK.
AXPlatformNodeBase::Init(delegate);
- g_unique_id_map.Get()[GetUniqueId()] = this;
DataChanged();
}
@@ -1831,6 +2164,93 @@ void AXPlatformNodeAuraLinux::OnExpandedStateChanged(bool is_expanded) {
is_expanded);
}
+void AXPlatformNodeAuraLinux::OnMenuPopupStart() {
+ AtkObject* parent_frame = FindAtkObjectParentFrame(atk_object_);
+ if (!parent_frame)
+ return;
+
+ // Exit early if kMenuPopupStart is sent multiple times for the same menu.
+ std::vector<AtkObject*>& active_menus = GetActiveMenus();
+ bool menu_already_open = !active_menus.empty();
+ if (menu_already_open && active_menus.back() == atk_object_)
+ return;
+
+ // We also want to inform the AT that menu the is now showing. Normally this
+ // event is not fired because the menu will be created with the
+ // ATK_STATE_SHOWING already set to TRUE.
+ atk_object_notify_state_change(atk_object_, ATK_STATE_SHOWING, TRUE);
+
+ // We need to compute this before modifying the active menu stack.
+ AtkObject* previous_active_frame = ComputeActiveTopLevelFrame();
+
+ active_menus.push_back(atk_object_);
+
+ // We exit early if the newly activated menu has the same AtkWindow as the
+ // previous one.
+ if (previous_active_frame == parent_frame)
+ return;
+ if (previous_active_frame) {
+ g_signal_emit_by_name(previous_active_frame, "deactivate");
+ atk_object_notify_state_change(previous_active_frame, ATK_STATE_ACTIVE,
+ FALSE);
+ }
+ g_signal_emit_by_name(parent_frame, "activate");
+ atk_object_notify_state_change(parent_frame, ATK_STATE_ACTIVE, TRUE);
+}
+
+void AXPlatformNodeAuraLinux::OnMenuPopupHide() {
+ AtkObject* parent_frame = FindAtkObjectParentFrame(atk_object_);
+ if (!parent_frame)
+ return;
+
+ atk_object_notify_state_change(atk_object_, ATK_STATE_SHOWING, FALSE);
+
+ // kMenuPopupHide may be called multiple times for the same menu, so only
+ // remove it if our parent frame matches the most recently opened menu.
+ std::vector<AtkObject*>& active_menus = GetActiveMenus();
+ if (active_menus.empty())
+ return;
+
+ // When multiple levels of menu are closed at once, they may be hidden out
+ // of order. When this happens, we just remove the open menu from the stack.
+ if (active_menus.back() != atk_object_) {
+ auto it =
+ std::find(active_menus.rbegin(), active_menus.rend(), atk_object_);
+ if (it != active_menus.rend()) {
+ // We used a reverse iterator, so we need to convert it into a normal
+ // iterator to use it for std::vector::erase(...).
+ auto to_remove = --(it.base());
+ active_menus.erase(to_remove);
+ }
+ return;
+ }
+
+ active_menus.pop_back();
+
+ // We exit early if the newly activated menu has the same AtkWindow as the
+ // previous one.
+ AtkObject* new_active_item = ComputeActiveTopLevelFrame();
+ if (new_active_item == parent_frame)
+ return;
+ g_signal_emit_by_name(parent_frame, "deactivate");
+ atk_object_notify_state_change(parent_frame, ATK_STATE_ACTIVE, FALSE);
+ if (new_active_item) {
+ g_signal_emit_by_name(new_active_item, "activate");
+ atk_object_notify_state_change(new_active_item, ATK_STATE_ACTIVE, TRUE);
+ }
+}
+
+void AXPlatformNodeAuraLinux::OnMenuPopupEnd() {
+ if (!GetActiveMenus().empty() && g_active_top_level_frame &&
+ ComputeActiveTopLevelFrame() != g_active_top_level_frame) {
+ g_signal_emit_by_name(g_active_top_level_frame, "activate");
+ atk_object_notify_state_change(g_active_top_level_frame, ATK_STATE_ACTIVE,
+ TRUE);
+ }
+
+ GetActiveMenus().clear();
+}
+
void AXPlatformNodeAuraLinux::OnWindowActivated() {
AtkObject* parent_frame = FindAtkObjectParentFrame(atk_object_);
if (!parent_frame || parent_frame == g_active_top_level_frame)
@@ -1840,6 +2260,15 @@ void AXPlatformNodeAuraLinux::OnWindowActivated() {
g_signal_emit_by_name(parent_frame, "activate");
atk_object_notify_state_change(parent_frame, ATK_STATE_ACTIVE, TRUE);
+
+ // We also send a focus event for the currently focused element, so that
+ // the user knows where the focus is when the toplevel window regains focus.
+ if (g_current_focused &&
+ IsFrameAncestorOfAtkObject(parent_frame, g_current_focused)) {
+ g_signal_emit_by_name(g_current_focused, "focus-event", true);
+ atk_object_notify_state_change(ATK_OBJECT(g_current_focused),
+ ATK_STATE_FOCUSED, true);
+ }
}
void AXPlatformNodeAuraLinux::OnWindowDeactivated() {
@@ -1857,8 +2286,7 @@ void AXPlatformNodeAuraLinux::OnFocused() {
DCHECK(atk_object_);
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);
+ OnWindowActivated();
return;
}
@@ -1920,6 +2348,11 @@ bool AXPlatformNodeAuraLinux::SelectionAndFocusAreTheSame() {
return false;
}
+bool AXPlatformNodeAuraLinux::SupportsSelectionWithAtkSelection() {
+ return SupportsToggle(GetData().role) ||
+ GetData().role == ax::mojom::Role::kListBoxOption;
+}
+
void AXPlatformNodeAuraLinux::OnValueChanged() {
DCHECK(atk_object_);
@@ -1945,6 +2378,21 @@ void AXPlatformNodeAuraLinux::OnValueChanged() {
void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent(
ax::mojom::Event event_type) {
switch (event_type) {
+ // There are three types of messages that we receive for popup menus. Each
+ // time a popup menu is shown, we get a kMenuPopupStart message. This
+ // includes if the menu is hidden and then re-shown. When a menu is hidden
+ // we receive the kMenuPopupHide message. Finally, when the entire menu is
+ // closed we receive the kMenuPopupEnd message for the parent menu and all
+ // of the submenus that were opened when navigating through the menu.
+ case ax::mojom::Event::kMenuPopupEnd:
+ OnMenuPopupEnd();
+ break;
+ case ax::mojom::Event::kMenuPopupHide:
+ OnMenuPopupHide();
+ break;
+ case ax::mojom::Event::kMenuPopupStart:
+ OnMenuPopupStart();
+ break;
case ax::mojom::Event::kCheckedStateChanged:
OnCheckedStateChanged();
break;
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
index b2b7f85da63..af70b463906 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -48,7 +48,7 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
AtkRole GetAtkRole();
void GetAtkState(AtkStateSet* state_set);
- void GetAtkRelations(AtkRelationSet* atk_relation_set);
+ AtkRelationSet* GetAtkRelations();
void GetExtents(gint* x, gint* y, gint* width, gint* height,
AtkCoordType coord_type);
void GetPosition(gint* x, gint* y, AtkCoordType coord_type);
@@ -65,8 +65,6 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
gint* x, gint* y, gint* width, gint* height,
AtkCoordType coord_type);
- static AXPlatformNodeAuraLinux* GetFromUniqueId(int32_t unique_id);
-
// AtkDocument helpers
const gchar* GetDocumentAttributeValue(const gchar* attribute) const;
AtkAttributeSet* GetDocumentAttributes() const;
@@ -83,9 +81,13 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
void OnFocused();
void OnWindowActivated();
void OnWindowDeactivated();
+ void OnMenuPopupStart();
+ void OnMenuPopupHide();
+ void OnMenuPopupEnd();
void OnSelected();
void OnValueChanged();
+ bool SupportsSelectionWithAtkSelection();
bool SelectionAndFocusAreTheSame();
// AXPlatformNode overrides.
@@ -128,6 +130,7 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
GType GetAccessibilityGType();
AtkObject* CreateAtkObject();
void DestroyAtkObjects();
+ void AddRelationToSet(AtkRelationSet*, AtkRelationType, int target_id);
// The AtkStateType for a checkable node can vary depending on the role.
AtkStateType GetAtkStateTypeForCheckableNode();
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 f0dd65e3f6c..98abda2e9ab 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -8,6 +8,9 @@
#include <atk/atk.h>
+#include <utility>
+#include <vector>
+
#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"
@@ -23,14 +26,24 @@ class AXPlatformNodeAuraLinuxTest : public AXPlatformNodeTest {
void SetUp() override {}
protected:
- AtkObject* AtkObjectFromNode(AXNode* node) {
+ AXPlatformNodeAuraLinux* GetPlatformNode(AXNode* node) {
TestAXNodeWrapper* wrapper =
TestAXNodeWrapper::GetOrCreate(tree_.get(), node);
if (!wrapper)
return nullptr;
- AXPlatformNode* ax_platform_node = wrapper->ax_platform_node();
- AtkObject* atk_object = ax_platform_node->GetNativeViewAccessible();
- return atk_object;
+ return static_cast<AXPlatformNodeAuraLinux*>(wrapper->ax_platform_node());
+ }
+
+ AXPlatformNodeAuraLinux* GetRootPlatformNode() {
+ return GetPlatformNode(GetRootNode());
+ }
+
+ AtkObject* AtkObjectFromNode(AXNode* node) {
+ if (AXPlatformNode* ax_platform_node = GetPlatformNode(node)) {
+ return ax_platform_node->GetNativeViewAccessible();
+ } else {
+ return nullptr;
+ }
}
TestAXNodeWrapper* GetRootWrapper() {
@@ -38,14 +51,6 @@ class AXPlatformNodeAuraLinuxTest : public AXPlatformNodeTest {
}
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(
@@ -585,11 +590,6 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectIntAttributes) {
ax::mojom::IntAttribute::kHierarchicalLevel,
"level");
TestAtkObjectIntAttribute(root_node, root_atk_object,
- ax::mojom::IntAttribute::kSetSize, "setsize");
- TestAtkObjectIntAttribute(root_node, root_atk_object,
- ax::mojom::IntAttribute::kPosInSet, "posinset");
-
- TestAtkObjectIntAttribute(root_node, root_atk_object,
ax::mojom::IntAttribute::kAriaColumnCount,
"colcount", ax::mojom::Role::kTable);
TestAtkObjectIntAttribute(root_node, root_atk_object,
@@ -956,6 +956,46 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkTextCharacterGranularity) {
g_object_unref(root_obj);
}
+class ActivationTester {
+ public:
+ explicit ActivationTester(AtkObject* target) : target_(target) {
+ auto callback = G_CALLBACK(+[](AtkWindow*, bool* flag) { *flag = true; });
+ activate_id_ =
+ g_signal_connect(target, "activate", callback, &saw_activate_);
+ deactivate_id_ =
+ g_signal_connect(target, "deactivate", callback, &saw_deactivate_);
+
+ DCHECK(activate_id_);
+ DCHECK(deactivate_id_);
+ DCHECK(activate_id_ != deactivate_id_);
+ }
+
+ bool IsActivatedInStateSet() {
+ AtkStateSet* state_set = atk_object_ref_state_set(target_);
+ EXPECT_TRUE(ATK_IS_STATE_SET(state_set));
+ bool in_state_set =
+ atk_state_set_contains_state(state_set, ATK_STATE_ACTIVE);
+ g_object_unref(state_set);
+ return in_state_set;
+ }
+
+ void Reset() {
+ saw_activate_ = false;
+ saw_deactivate_ = false;
+ }
+
+ virtual ~ActivationTester() {
+ g_signal_handler_disconnect(target_, activate_id_);
+ g_signal_handler_disconnect(target_, deactivate_id_);
+ }
+
+ AtkObject* target_;
+ bool saw_activate_ = false;
+ bool saw_deactivate_ = false;
+ gulong activate_id_ = 0;
+ gulong deactivate_id_ = 0;
+};
+
//
// AtkWindow interface and active state
//
@@ -964,7 +1004,13 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkWindowActive) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kWindow;
- Init(root);
+ root.child_ids.push_back(2);
+
+ AXNodeData child;
+ child.id = 2;
+ child.role = ax::mojom::Role::kCheckBox;
+
+ Init(root, child);
AtkObject* root_atk_object(GetRootAtkObject());
EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
@@ -972,42 +1018,498 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkWindowActive) {
EXPECT_TRUE(ATK_IS_WINDOW(root_atk_object));
- bool saw_activate = false;
- bool saw_deactivate = false;
+ AXNode* checkbox_node = GetRootNode()->children()[0];
+ AtkObject* checkbox_atk_obj = AtkObjectFromNode(checkbox_node);
- 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);
+ // Focus the checkbox to ensure that it also gets new focus events when
+ // the toplevel window goes from unfocused to focused.
+ GetPlatformNode(checkbox_node)
+ ->NotifyAccessibilityEvent(ax::mojom::Event::kFocus);
- 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);
+ bool saw_active_focus_state_change = false;
+ g_signal_connect(checkbox_atk_obj, "state-change",
+ G_CALLBACK(+[](AtkObject* atkobject, gchar* state_changed,
+ gboolean new_value, bool* flag) {
+ if (!g_strcmp0(state_changed, "focused") && new_value)
+ *flag = true;
+ }),
+ &saw_active_focus_state_change);
+
+ {
+ ActivationTester tester(root_atk_object);
+ EXPECT_FALSE(tester.IsActivatedInStateSet());
+ static_cast<AXPlatformNodeAuraLinux*>(GetRootPlatformNode())
+ ->NotifyAccessibilityEvent(ax::mojom::Event::kWindowActivated);
+ EXPECT_TRUE(tester.saw_activate_);
+ EXPECT_FALSE(tester.saw_deactivate_);
+ EXPECT_TRUE(tester.IsActivatedInStateSet());
+ EXPECT_TRUE(saw_active_focus_state_change);
+ }
+
+ {
+ saw_active_focus_state_change = false;
+
+ ActivationTester tester(root_atk_object);
+ static_cast<AXPlatformNodeAuraLinux*>(GetRootPlatformNode())
+ ->NotifyAccessibilityEvent(ax::mojom::Event::kWindowDeactivated);
+ EXPECT_FALSE(tester.saw_activate_);
+ EXPECT_TRUE(tester.saw_deactivate_);
+ EXPECT_FALSE(tester.IsActivatedInStateSet());
+ EXPECT_FALSE(saw_active_focus_state_change);
+ }
+
+ g_object_unref(root_atk_object);
+}
+
+TEST_F(AXPlatformNodeAuraLinuxTest, TestFocusTriggersAtkWindowActive) {
+ AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kWindow;
+ root.child_ids.push_back(2);
+
+ AXNodeData child_node_data;
+ child_node_data.id = 2;
+ child_node_data.role = ax::mojom::Role::kButton;
+
+ Init(root, child_node_data);
+
+ 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));
+
+ AXNode* child_node = GetRootNode()->children()[0];
+
+ // A focus event on a child node should not cause the window to
+ // activate.
+ {
+ ActivationTester tester(root_atk_object);
+ GetPlatformNode(child_node)
+ ->NotifyAccessibilityEvent(ax::mojom::Event::kFocus);
+ EXPECT_FALSE(tester.saw_activate_);
+ EXPECT_FALSE(tester.saw_deactivate_);
+ EXPECT_FALSE(tester.IsActivatedInStateSet());
+ }
+
+ // A focus event on the window itself should cause the window to activate.
+ {
+ ActivationTester tester(root_atk_object);
+ GetRootPlatformNode()->NotifyAccessibilityEvent(ax::mojom::Event::kFocus);
+ EXPECT_TRUE(tester.saw_activate_);
+ EXPECT_FALSE(tester.saw_deactivate_);
+ EXPECT_TRUE(tester.IsActivatedInStateSet());
+ }
+
+ // Since the window is already active, we shouldn't see another activation
+ // event, but it should still be active.
+ {
+ ActivationTester tester(root_atk_object);
+ GetRootPlatformNode()->NotifyAccessibilityEvent(ax::mojom::Event::kFocus);
+ EXPECT_FALSE(tester.saw_activate_);
+ EXPECT_FALSE(tester.saw_deactivate_);
+ EXPECT_TRUE(tester.IsActivatedInStateSet());
+ }
+
+ g_object_unref(root_atk_object);
+}
+
+TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkPopupWindowActive) {
+ AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kApplication;
+ root.child_ids.push_back(2);
+ root.child_ids.push_back(3);
+
+ AXNodeData window_node_data;
+ window_node_data.id = 2;
+ window_node_data.role = ax::mojom::Role::kWindow;
+
+ AXNodeData menu_node_data;
+ menu_node_data.id = 3;
+ menu_node_data.role = ax::mojom::Role::kWindow;
+ menu_node_data.child_ids.push_back(4);
- static_cast<AXPlatformNodeAuraLinux*>(GetRootPlatformNode())
+ AXNodeData menu_item_data;
+ menu_item_data.id = 4;
+
+ Init(root, window_node_data, menu_node_data, menu_item_data);
+
+ AtkObject* root_atk_object(GetRootAtkObject());
+ EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
+ g_object_ref(root_atk_object);
+
+ AXNode* window_node = GetRootNode()->children()[0];
+ AtkObject* window_atk_node(AtkObjectFromNode(window_node));
+
+ ActivationTester toplevel_tester(window_atk_node);
+ GetPlatformNode(window_node)
->NotifyAccessibilityEvent(ax::mojom::Event::kWindowActivated);
- EXPECT_TRUE(saw_activate);
- EXPECT_FALSE(saw_deactivate);
+ EXPECT_TRUE(toplevel_tester.saw_activate_);
+ EXPECT_FALSE(toplevel_tester.saw_deactivate_);
+ EXPECT_TRUE(toplevel_tester.IsActivatedInStateSet());
- 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);
+ toplevel_tester.Reset();
- saw_activate = false;
- saw_deactivate = false;
+ AXNode* menu_node = GetRootNode()->children()[1];
+ AtkObject* menu_atk_node(AtkObjectFromNode(menu_node));
+ {
+ ActivationTester tester(menu_atk_node);
+ GetPlatformNode(menu_node)->NotifyAccessibilityEvent(
+ ax::mojom::Event::kMenuPopupStart);
+ EXPECT_TRUE(tester.saw_activate_);
+ EXPECT_FALSE(tester.saw_deactivate_);
+ EXPECT_TRUE(tester.IsActivatedInStateSet());
+ }
- static_cast<AXPlatformNodeAuraLinux*>(GetRootPlatformNode())
- ->NotifyAccessibilityEvent(ax::mojom::Event::kWindowDeactivated);
- EXPECT_FALSE(saw_activate);
- EXPECT_TRUE(saw_deactivate);
+ EXPECT_FALSE(toplevel_tester.saw_activate_);
+ EXPECT_TRUE(toplevel_tester.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);
+ toplevel_tester.Reset();
+
+ {
+ ActivationTester tester(menu_atk_node);
+ GetPlatformNode(menu_node)->NotifyAccessibilityEvent(
+ ax::mojom::Event::kMenuPopupHide);
+ EXPECT_FALSE(tester.saw_activate_);
+ EXPECT_TRUE(tester.saw_deactivate_);
+ EXPECT_FALSE(tester.IsActivatedInStateSet());
+ }
+
+ {
+ ActivationTester tester(menu_atk_node);
+ GetPlatformNode(menu_node)->NotifyAccessibilityEvent(
+ ax::mojom::Event::kMenuPopupEnd);
+ EXPECT_FALSE(tester.saw_activate_);
+ EXPECT_FALSE(tester.saw_deactivate_);
+ EXPECT_FALSE(tester.IsActivatedInStateSet());
+ }
+
+ // Now that the menu is definitively closed, activation should have returned
+ // to the previously activated toplevel frame.
+ EXPECT_TRUE(toplevel_tester.saw_activate_);
+ EXPECT_FALSE(toplevel_tester.saw_deactivate_);
+
+ // No we test opening the menu and closing it without hiding any submenus. The
+ // toplevel should lose and then regain focus.
+ toplevel_tester.Reset();
+
+ GetPlatformNode(menu_node)->NotifyAccessibilityEvent(
+ ax::mojom::Event::kMenuPopupStart);
+ GetPlatformNode(menu_node)->NotifyAccessibilityEvent(
+ ax::mojom::Event::kMenuPopupEnd);
+ EXPECT_TRUE(toplevel_tester.saw_activate_);
+ EXPECT_TRUE(toplevel_tester.saw_deactivate_);
+
+ g_object_unref(root_atk_object);
+}
+
+TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkSelectionInterface) {
+ AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kListBox;
+ root.child_ids.push_back(2);
+ root.child_ids.push_back(3);
+ root.child_ids.push_back(4);
+ root.child_ids.push_back(5);
+
+ AXNodeData item_1;
+ item_1.id = 2;
+ item_1.role = ax::mojom::Role::kListBoxOption;
+
+ AXNodeData item_2;
+ item_2.id = 3;
+ item_2.role = ax::mojom::Role::kListBoxOption;
+
+ AXNodeData item_3;
+ item_3.id = 4;
+ item_3.role = ax::mojom::Role::kListBoxOption;
+
+ // Add a final item which is not selectable.
+ AXNodeData item_4;
+ item_4.id = 5;
+ item_4.role = ax::mojom::Role::kListItem;
+
+ AXTreeUpdate update;
+ update.root_id = 1;
+ update.nodes.push_back(root);
+ update.nodes.push_back(item_1);
+ update.nodes.push_back(item_2);
+ update.nodes.push_back(item_3);
+ update.nodes.push_back(item_4);
+ Init(update);
+
+ AtkObject* root_atk_object(GetRootAtkObject());
+ EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
+ g_object_ref(root_atk_object);
+
+ ASSERT_TRUE(ATK_IS_SELECTION(root_atk_object));
+
+ ASSERT_TRUE(ATK_IS_SELECTION(root_atk_object));
+ AtkSelection* selection = ATK_SELECTION(root_atk_object);
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 0);
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 0));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 1));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 2));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 3));
+
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, -1));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, -100));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 4));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 3000));
+
+ ASSERT_TRUE(atk_selection_select_all_selection(selection));
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 3);
+ ASSERT_TRUE(atk_selection_is_child_selected(selection, 0));
+ ASSERT_TRUE(atk_selection_is_child_selected(selection, 1));
+ ASSERT_TRUE(atk_selection_is_child_selected(selection, 2));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 3));
+
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, -1));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, -100));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 4));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 3000));
+
+ ASSERT_TRUE(atk_selection_clear_selection(selection));
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 0);
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 0));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 1));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 2));
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 3));
+
+ ASSERT_TRUE(atk_selection_add_selection(selection, 1));
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 1);
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 0));
+ ASSERT_TRUE(atk_selection_is_child_selected(selection, 1));
+
+ // The index to this function is the index into the selected elements, not
+ // into the children.
+ ASSERT_TRUE(atk_selection_remove_selection(selection, 0));
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 0);
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 1));
+
+ // We should not be able to select an item with a role that is not
+ // selectable.
+ ASSERT_FALSE(atk_selection_add_selection(selection, 3));
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 0);
+ ASSERT_FALSE(atk_selection_is_child_selected(selection, 3));
+
+ // Test some out of bounds use of atk_selection_add_selection.
+ ASSERT_FALSE(atk_selection_add_selection(selection, -1));
+ ASSERT_FALSE(atk_selection_add_selection(selection, -100));
+ ASSERT_FALSE(atk_selection_add_selection(selection, 4));
+ ASSERT_FALSE(atk_selection_add_selection(selection, 100));
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 0);
+
+ ASSERT_TRUE(atk_selection_select_all_selection(selection));
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 3);
+ ASSERT_FALSE(atk_selection_remove_selection(selection, -1));
+ ASSERT_FALSE(atk_selection_remove_selection(selection, -100));
+ ASSERT_FALSE(atk_selection_remove_selection(selection, 4));
+ ASSERT_FALSE(atk_selection_remove_selection(selection, 100));
+ ASSERT_EQ(atk_selection_get_selection_count(selection), 3);
g_object_unref(root_atk_object);
}
+// Tests GetPosInSet() and GetSetSize() functions of AXPlatformNodeBase.
+// PosInSet and SetSize must be tested separately from other IntAttributes
+// because they can be either assigned values or calculated dynamically.
+TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectSetSizePosInSet) {
+ AXTreeUpdate update;
+ update.root_id = 1;
+ update.nodes.resize(4);
+ update.nodes[0].id = 1;
+ update.nodes[0].role = ax::mojom::Role::kRadioGroup;
+ update.nodes[0].child_ids = {2, 3, 4};
+ update.nodes[1].id = 2;
+ update.nodes[1].role =
+ ax::mojom::Role::kRadioButton; // kRadioButton posinset = 2, setsize = 5.
+ update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 2);
+ update.nodes[2].id = 3;
+ update.nodes[2].role =
+ ax::mojom::Role::kRadioButton; // kRadioButton posinset = 3, setsize = 5.
+ update.nodes[3].id = 4;
+ update.nodes[3].role =
+ ax::mojom::Role::kRadioButton; // kRadioButton posinset = 5, stesize = 5
+ update.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 5);
+ Init(update);
+
+ AXNode* radiobutton1 = GetRootNode()->children()[0];
+ AtkObject* radiobutton1_atk_object(AtkObjectFromNode(radiobutton1));
+ EXPECT_TRUE(ATK_IS_OBJECT(radiobutton1_atk_object));
+ g_object_ref(radiobutton1_atk_object);
+
+ AXNode* radiobutton2 = GetRootNode()->children()[1];
+ AtkObject* radiobutton2_atk_object(AtkObjectFromNode(radiobutton2));
+ EXPECT_TRUE(ATK_IS_OBJECT(radiobutton2_atk_object));
+ g_object_ref(radiobutton2_atk_object);
+
+ AXNode* radiobutton3 = GetRootNode()->children()[2];
+ AtkObject* radiobutton3_atk_object(AtkObjectFromNode(radiobutton3));
+ EXPECT_TRUE(ATK_IS_OBJECT(radiobutton3_atk_object));
+ g_object_ref(radiobutton3_atk_object);
+
+ // Notice that setsize was never assigned to any of the kRadioButtons, but was
+ // inferred.
+ EnsureAtkObjectHasAttributeWithValue(radiobutton1_atk_object, "posinset",
+ "2");
+ EnsureAtkObjectHasAttributeWithValue(radiobutton1_atk_object, "setsize", "5");
+ EnsureAtkObjectHasAttributeWithValue(radiobutton2_atk_object, "posinset",
+ "3");
+ EnsureAtkObjectHasAttributeWithValue(radiobutton2_atk_object, "setsize", "5");
+ EnsureAtkObjectHasAttributeWithValue(radiobutton3_atk_object, "posinset",
+ "5");
+ EnsureAtkObjectHasAttributeWithValue(radiobutton3_atk_object, "setsize", "5");
+}
+
+TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkRelations) {
+ AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
+ root.AddIntAttribute(ax::mojom::IntAttribute::kDetailsId, 2);
+
+ AXNodeData child1;
+ child1.id = 2;
+ child1.role = ax::mojom::Role::kStaticText;
+
+ root.child_ids.push_back(2);
+
+ AXNodeData child2;
+ child2.id = 3;
+ child2.role = ax::mojom::Role::kStaticText;
+ std::vector<int32_t> labelledby_ids = {1, 4};
+ child2.AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds,
+ labelledby_ids);
+
+ root.child_ids.push_back(3);
+
+ AXNodeData child3;
+ child3.id = 4;
+ child3.role = ax::mojom::Role::kStaticText;
+ child3.AddIntAttribute(ax::mojom::IntAttribute::kDetailsId, 2);
+ child3.AddIntAttribute(ax::mojom::IntAttribute::kMemberOfId, 1);
+
+ root.child_ids.push_back(4);
+
+ Init(root, child1, child2, child3);
+
+ // We don't test relations that are too new for the runtime version of ATK.
+ GEnumClass* enum_class =
+ G_ENUM_CLASS(g_type_class_ref(atk_relation_type_get_type()));
+ int max_relation_type = enum_class->maximum;
+ g_type_class_unref(enum_class);
+
+ auto assert_contains_relation = [&](AtkObject* object, AtkObject* target,
+ AtkRelationType relation) {
+ if (relation > max_relation_type)
+ return;
+
+ AtkRelationSet* relations = atk_object_ref_relation_set(object);
+ ASSERT_TRUE(atk_relation_set_contains(relations, relation));
+ ASSERT_TRUE(atk_relation_set_contains_target(relations, relation, target));
+ g_object_unref(G_OBJECT(relations));
+ };
+
+ AtkObject* root_atk_object(GetRootAtkObject());
+ EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
+ g_object_ref(root_atk_object);
+
+ AtkObject* atk_child1(AtkObjectFromNode(GetRootNode()->children()[0]));
+ AtkObject* atk_child2(AtkObjectFromNode(GetRootNode()->children()[1]));
+ AtkObject* atk_child3(AtkObjectFromNode(GetRootNode()->children()[2]));
+
+ assert_contains_relation(root_atk_object, atk_child1, ATK_RELATION_DETAILS);
+ assert_contains_relation(atk_child1, root_atk_object,
+ ATK_RELATION_DETAILS_FOR);
+ assert_contains_relation(atk_child3, atk_child1, ATK_RELATION_DETAILS);
+ assert_contains_relation(atk_child1, atk_child3, ATK_RELATION_DETAILS_FOR);
+
+ assert_contains_relation(atk_child2, root_atk_object,
+ ATK_RELATION_LABELLED_BY);
+ assert_contains_relation(root_atk_object, atk_child2, ATK_RELATION_LABEL_FOR);
+ assert_contains_relation(atk_child2, atk_child3, ATK_RELATION_LABELLED_BY);
+ assert_contains_relation(atk_child3, atk_child2, ATK_RELATION_LABEL_FOR);
+
+ assert_contains_relation(atk_child3, root_atk_object, ATK_RELATION_MEMBER_OF);
+
+ g_object_unref(root_atk_object);
+}
+
+TEST_F(AXPlatformNodeAuraLinuxTest, TestAllReverseAtkRelations) {
+ // We don't test relations that are too new for the runtime version of ATK.
+ GEnumClass* enum_class =
+ G_ENUM_CLASS(g_type_class_ref(atk_relation_type_get_type()));
+ int max_relation_type = enum_class->maximum;
+ g_type_class_unref(enum_class);
+
+ auto test_relation = [&](auto attribute_setter,
+ AtkRelationType expected_relation,
+ AtkRelationType expected_reverse_relation) {
+ if (expected_relation > max_relation_type ||
+ expected_reverse_relation > max_relation_type)
+ return;
+
+ AXNodeData root_data;
+ root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
+ attribute_setter(&root_data, 2);
+
+ AXNodeData child_data;
+ child_data.id = 2;
+ child_data.role = ax::mojom::Role::kStaticText;
+ root_data.child_ids.push_back(2);
+ Init(root_data, child_data);
+
+ AtkObject* source(GetRootAtkObject());
+ AtkObject* target(AtkObjectFromNode(GetRootNode()->children()[0]));
+
+ AtkRelationSet* relations = atk_object_ref_relation_set(source);
+ ASSERT_TRUE(atk_relation_set_contains(relations, expected_relation));
+ ASSERT_TRUE(
+ atk_relation_set_contains_target(relations, expected_relation, target));
+ g_object_unref(G_OBJECT(relations));
+
+ relations = atk_object_ref_relation_set(target);
+ ASSERT_TRUE(
+ atk_relation_set_contains(relations, expected_reverse_relation));
+ ASSERT_TRUE(atk_relation_set_contains_target(
+ relations, expected_reverse_relation, source));
+ g_object_unref(G_OBJECT(relations));
+ };
+
+ auto test_int_relation = [&](ax::mojom::IntAttribute relation,
+ AtkRelationType expected_relation,
+ AtkRelationType expected_reverse_relation) {
+ auto setter = [&](AXNodeData* data, int target_id) {
+ data->AddIntAttribute(relation, target_id);
+ };
+ test_relation(setter, expected_relation, expected_reverse_relation);
+ };
+
+ auto test_int_list_relation = [&](ax::mojom::IntListAttribute relation,
+ AtkRelationType expected_relation,
+ AtkRelationType expected_reverse_relation) {
+ auto setter = [&](AXNodeData* data, int target_id) {
+ std::vector<int32_t> ids = {target_id};
+ data->AddIntListAttribute(relation, ids);
+ };
+ test_relation(setter, expected_relation, expected_reverse_relation);
+ };
+
+ test_int_relation(ax::mojom::IntAttribute::kDetailsId, ATK_RELATION_DETAILS,
+ ATK_RELATION_DETAILS_FOR);
+ test_int_relation(ax::mojom::IntAttribute::kErrormessageId,
+ ATK_RELATION_ERROR_MESSAGE, ATK_RELATION_ERROR_FOR);
+ test_int_list_relation(ax::mojom::IntListAttribute::kControlsIds,
+ ATK_RELATION_CONTROLLER_FOR,
+ ATK_RELATION_CONTROLLED_BY);
+ test_int_list_relation(ax::mojom::IntListAttribute::kDescribedbyIds,
+ ATK_RELATION_DESCRIBED_BY,
+ ATK_RELATION_DESCRIPTION_FOR);
+ test_int_list_relation(ax::mojom::IntListAttribute::kFlowtoIds,
+ ATK_RELATION_FLOWS_TO, ATK_RELATION_FLOWS_FROM);
+ test_int_list_relation(ax::mojom::IntListAttribute::kLabelledbyIds,
+ ATK_RELATION_LABELLED_BY, ATK_RELATION_LABEL_FOR);
+}
+
} // 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 b321c498745..bbe67573a63 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base.cc
@@ -5,6 +5,7 @@
#include "ui/accessibility/platform/ax_platform_node_base.h"
#include <string>
+#include <unordered_map>
#include <utility>
#include <vector>
@@ -17,12 +18,18 @@
#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
+#include "ui/accessibility/platform/compute_attributes.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace ui {
const base::char16 AXPlatformNodeBase::kEmbeddedCharacter = L'\xfffc';
+// Map from each AXPlatformNode's unique id to its instance.
+using UniqueIdMap = std::unordered_map<int32_t, AXPlatformNode*>;
+base::LazyInstance<UniqueIdMap>::Leaky g_unique_id_map =
+ LAZY_INSTANCE_INITIALIZER;
+
#if !BUILDFLAG_INTERNAL_HAS_NATIVE_ACCESSIBILITY()
// static
AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
@@ -32,12 +39,30 @@ AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
}
#endif
+// static
+AXPlatformNode* AXPlatformNodeBase::GetFromUniqueId(int32_t unique_id) {
+ UniqueIdMap* unique_ids = g_unique_id_map.Pointer();
+ auto iter = unique_ids->find(unique_id);
+ if (iter != unique_ids->end())
+ return iter->second;
+
+ return nullptr;
+}
+
+// static
+size_t AXPlatformNodeBase::GetInstanceCountForTesting() {
+ return g_unique_id_map.Get().size();
+}
+
AXPlatformNodeBase::AXPlatformNodeBase() = default;
AXPlatformNodeBase::~AXPlatformNodeBase() = default;
void AXPlatformNodeBase::Init(AXPlatformNodeDelegate* delegate) {
delegate_ = delegate;
+
+ // This must be called after assigning our delegate.
+ g_unique_id_map.Get()[GetUniqueId()] = this;
}
const AXNodeData& AXPlatformNodeBase::GetData() const {
@@ -78,7 +103,10 @@ int AXPlatformNodeBase::GetIndexInParent() {
// AXPlatformNode overrides.
void AXPlatformNodeBase::Destroy() {
+ g_unique_id_map.Get().erase(GetUniqueId());
+
AXPlatformNode::Destroy();
+
delegate_ = nullptr;
Dispose();
}
@@ -914,9 +942,10 @@ void AXPlatformNodeBase::AddAttributeToList(
const char* name,
PlatformAttributeList* attributes) {
DCHECK(attributes);
- int value;
- if (GetIntAttribute(attribute, &value)) {
- std::string str_value = base::IntToString(value);
+
+ auto maybe_value = ComputeAttribute(delegate_, attribute);
+ if (maybe_value.has_value()) {
+ std::string str_value = base::IntToString(maybe_value.value());
AddAttributeToList(name, str_value, attributes);
}
}
@@ -982,6 +1011,14 @@ void AXPlatformNodeBase::AddAttributeToList(const char* name,
PlatformAttributeList* attributes) {
}
+int32_t AXPlatformNodeBase::GetPosInSet() const {
+ return delegate_->GetPosInSet();
+}
+
+int32_t AXPlatformNodeBase::GetSetSize() const {
+ return delegate_->GetSetSize();
+}
+
// 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 d080cb1bff9..0b89a8f8ab8 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base.h
@@ -13,7 +13,7 @@
#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"
+#include "ui/base/buildflags.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
@@ -199,6 +199,12 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
// child object appears.
static const base::char16 kEmbeddedCharacter;
+ // Get a node given its unique id or null in the case that the id is unknown.
+ static AXPlatformNode* GetFromUniqueId(int32_t unique_id);
+
+ // Return the number of instances of AXPlatformNodeBase, for leak testing.
+ static size_t GetInstanceCountForTesting();
+
//
// Delegate. This is a weak reference which owns |this|.
//
@@ -284,6 +290,9 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
// embedded element character.
AXHypertext ComputeHypertext();
+ int32_t GetPosInSet() const;
+ int32_t GetSetSize() const;
+
private:
DISALLOW_COPY_AND_ASSIGN(AXPlatformNodeBase);
};
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
index 423ec2eeb92..f569559345c 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -117,19 +117,41 @@ class AX_EXPORT AXPlatformNodeDelegate {
// Tables. All of these should be called on a node that's a table-like
// role.
//
-
- virtual int GetTableRowCount() const = 0;
- virtual int GetTableColCount() const = 0;
+ virtual bool IsTable() const = 0;
+ virtual int32_t GetTableColCount() const = 0;
+ virtual int32_t GetTableRowCount() const = 0;
+ virtual int32_t GetTableAriaColCount() const = 0;
+ virtual int32_t GetTableAriaRowCount() const = 0;
+ virtual int32_t GetTableCellCount() 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;
+
+ // Table row-like nodes.
+ virtual bool IsTableRow() const = 0;
+ virtual int32_t GetTableRowRowIndex() const = 0;
+
+ // Table cell-like nodes.
+ virtual bool IsTableCellOrHeader() const = 0;
virtual int32_t GetTableCellIndex() const = 0;
+ virtual int32_t GetTableCellColIndex() const = 0;
+ virtual int32_t GetTableCellRowIndex() const = 0;
+ virtual int32_t GetTableCellColSpan() const = 0;
+ virtual int32_t GetTableCellRowSpan() const = 0;
+ virtual int32_t GetTableCellAriaColIndex() const = 0;
+ virtual int32_t GetTableCellAriaRowIndex() const = 0;
+ virtual int32_t GetCellId(int32_t row_index, int32_t col_index) const = 0;
virtual int32_t CellIndexToId(int32_t cell_index) const = 0;
+ // Ordered-set-like and item-like nodes.
+ virtual bool IsOrderedSetItem() const = 0;
+ virtual bool IsOrderedSet() const = 0;
+ virtual int32_t GetPosInSet() const = 0;
+ virtual int32_t GetSetSize() const = 0;
+
//
// Events.
//
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 fbbfed50168..d1aa8dbd235 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -70,6 +70,10 @@ AXPlatformNodeDelegateBase::GetTargetForNativeAccessibilityEvent() {
return gfx::kNullAcceleratedWidget;
}
+bool AXPlatformNodeDelegateBase::IsTable() const {
+ return false;
+}
+
int AXPlatformNodeDelegateBase::GetTableRowCount() const {
return 0;
}
@@ -78,6 +82,18 @@ int AXPlatformNodeDelegateBase::GetTableColCount() const {
return 0;
}
+int32_t AXPlatformNodeDelegateBase::GetTableAriaColCount() const {
+ return 0;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableAriaRowCount() const {
+ return 0;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableCellCount() const {
+ return 0;
+}
+
const std::vector<int32_t> AXPlatformNodeDelegateBase::GetColHeaderNodeIds()
const {
return std::vector<int32_t>();
@@ -98,6 +114,42 @@ const std::vector<int32_t> AXPlatformNodeDelegateBase::GetRowHeaderNodeIds(
return std::vector<int32_t>();
}
+bool AXPlatformNodeDelegateBase::IsTableRow() const {
+ return false;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableRowRowIndex() const {
+ return 0;
+}
+
+bool AXPlatformNodeDelegateBase::IsTableCellOrHeader() const {
+ return false;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableCellColIndex() const {
+ return 0;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableCellRowIndex() const {
+ return 0;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableCellColSpan() const {
+ return 0;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableCellRowSpan() const {
+ return 0;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableCellAriaColIndex() const {
+ return 0;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetTableCellAriaRowIndex() const {
+ return 0;
+}
+
int32_t AXPlatformNodeDelegateBase::GetCellId(int32_t row_index,
int32_t col_index) const {
return -1;
@@ -141,4 +193,20 @@ const AXUniqueId& AXPlatformNodeDelegateBase::GetUniqueId() const {
return *dummy_unique_id;
}
+bool AXPlatformNodeDelegateBase::IsOrderedSetItem() const {
+ return false;
+}
+
+bool AXPlatformNodeDelegateBase::IsOrderedSet() const {
+ return false;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetPosInSet() const {
+ return 0;
+}
+
+int32_t AXPlatformNodeDelegateBase::GetSetSize() const {
+ return 0;
+}
+
} // namespace ui
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 4a7ad1a8e84..20a2c9991d6 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -92,19 +92,41 @@ class AX_EXPORT AXPlatformNodeDelegateBase : public AXPlatformNodeDelegate {
// Tables. All of these should be called on a node that's a table-like
// role.
//
-
- int GetTableRowCount() const override;
- int GetTableColCount() const override;
+ bool IsTable() const override;
+ int32_t GetTableColCount() const override;
+ int32_t GetTableRowCount() const override;
+ int32_t GetTableAriaColCount() const override;
+ int32_t GetTableAriaRowCount() const override;
+ int32_t GetTableCellCount() 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;
+
+ // Table row-like nodes.
+ bool IsTableRow() const override;
+ int32_t GetTableRowRowIndex() const override;
+
+ // Table cell-like nodes.
+ bool IsTableCellOrHeader() const override;
int32_t GetTableCellIndex() const override;
+ int32_t GetTableCellColIndex() const override;
+ int32_t GetTableCellRowIndex() const override;
+ int32_t GetTableCellColSpan() const override;
+ int32_t GetTableCellRowSpan() const override;
+ int32_t GetTableCellAriaColIndex() const override;
+ int32_t GetTableCellAriaRowIndex() const override;
+ int32_t GetCellId(int32_t row_index, int32_t col_index) const override;
int32_t CellIndexToId(int32_t cell_index) const override;
+ // Ordered-set-like and item-like nodes.
+ bool IsOrderedSetItem() const override;
+ bool IsOrderedSet() const override;
+ int32_t GetPosInSet() const override;
+ int32_t GetSetSize() const override;
+
//
// Events.
//
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
index 56d59f01608..0984d315df1 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
@@ -10,10 +10,10 @@
#include <map>
#include <set>
#include <string>
+#include <unordered_set>
#include <utility>
#include <vector>
-#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -42,7 +42,15 @@
// object is still valid, and then check that all pointer arguments are
// not NULL.
//
-
+#define UIA_VALIDATE_CALL() \
+ if (!GetDelegate()) \
+ return UIA_E_ELEMENTNOTAVAILABLE;
+#define UIA_VALIDATE_CALL_1_ARG(arg) \
+ if (!GetDelegate()) \
+ return UIA_E_ELEMENTNOTAVAILABLE; \
+ if (!arg) \
+ return E_INVALIDARG; \
+ *arg = {};
#define COM_OBJECT_VALIDATE() \
if (!GetDelegate()) \
return E_FAIL;
@@ -166,7 +174,7 @@ namespace ui {
namespace {
-typedef base::hash_set<AXPlatformNodeWin*> AXPlatformNodeWinSet;
+typedef std::unordered_set<AXPlatformNodeWin*> AXPlatformNodeWinSet;
// Set of all AXPlatformNodeWin objects that were the target of an
// alert event.
base::LazyInstance<AXPlatformNodeWinSet>::Leaky g_alert_targets =
@@ -205,11 +213,9 @@ const uint32_t kScreenReaderAndHTMLAccessibilityModes =
// IAccessible2UsageObserver
//
-IAccessible2UsageObserver::IAccessible2UsageObserver() {
-}
+IAccessible2UsageObserver::IAccessible2UsageObserver() {}
-IAccessible2UsageObserver::~IAccessible2UsageObserver() {
-}
+IAccessible2UsageObserver::~IAccessible2UsageObserver() {}
// static
base::ObserverList<IAccessible2UsageObserver>::Unchecked&
@@ -244,20 +250,6 @@ AXPlatformNode* AXPlatformNode::FromNativeViewAccessible(
return ax_platform_node.Get();
}
-using UniqueIdMap = base::hash_map<int32_t, AXPlatformNode*>;
-// Map from each AXPlatformNode's unique id to its instance.
-base::LazyInstance<UniqueIdMap>::Leaky g_unique_id_map =
- LAZY_INSTANCE_INITIALIZER;
-
-// static
-AXPlatformNode* AXPlatformNodeWin::GetFromUniqueId(int32_t unique_id) {
- UniqueIdMap* unique_ids = g_unique_id_map.Pointer();
- auto iter = unique_ids->find(unique_id);
- if (iter != unique_ids->end())
- return iter->second;
-
- return nullptr;
-}
//
// AXPlatformNodeWin
//
@@ -270,12 +262,6 @@ AXPlatformNodeWin::~AXPlatformNodeWin() {
void AXPlatformNodeWin::Init(AXPlatformNodeDelegate* delegate) {
AXPlatformNodeBase::Init(delegate);
- g_unique_id_map.Get()[GetUniqueId()] = this;
-}
-
-// static
-size_t AXPlatformNodeWin::GetInstanceCountForTesting() {
- return g_unique_id_map.Get().size();
}
void AXPlatformNodeWin::ClearOwnRelations() {
@@ -464,8 +450,6 @@ void AXPlatformNodeWin::Dispose() {
}
void AXPlatformNodeWin::Destroy() {
- g_unique_id_map.Get().erase(GetUniqueId());
-
RemoveAlertTarget();
// This will end up calling Dispose() which may result in deleting this object
@@ -618,7 +602,7 @@ IFACEMETHODIMP AXPlatformNodeWin::accLocation(LONG* x_left,
gfx::Rect bounds = target->GetDelegate()->GetUnclippedScreenBoundsRect();
*x_left = bounds.x();
*y_top = bounds.y();
- *width = bounds.width();
+ *width = bounds.width();
*height = bounds.height();
if (bounds.IsEmpty())
@@ -831,19 +815,8 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accName(VARIANT var_id, BSTR* name) {
observer.OnAccNameCalled();
}
- HRESULT result =
- target->GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName, name);
- if (FAILED(result) && MSAARole() == ROLE_SYSTEM_DOCUMENT && GetParent()) {
- // Hack: Some versions of JAWS crash if they get an empty name on
- // a document that's the child of an iframe, so always return a
- // nonempty string for this role. https://crbug.com/583057
- base::string16 str = L" ";
-
- *name = SysAllocString(str.c_str());
- DCHECK(*name);
- }
-
- return result;
+ return target->GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName,
+ name);
}
IFACEMETHODIMP AXPlatformNodeWin::get_accParent(IDispatch** disp_parent) {
@@ -1008,15 +981,15 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accSelection(VARIANT* selected) {
selected->vt = VT_DISPATCH;
selected->pdispVal = selected_nodes[0].Detach();
return S_OK;
- }
+ }
// Multiple items are selected.
- LONG selected_count = static_cast<LONG>(selected_nodes.size());
- auto* enum_variant = new base::win::EnumVariant(selected_count);
- enum_variant->AddRef();
- for (LONG i = 0; i < selected_count; ++i) {
- enum_variant->ItemAt(i)->vt = VT_DISPATCH;
- enum_variant->ItemAt(i)->pdispVal = selected_nodes[i].Detach();
+ LONG selected_count = static_cast<LONG>(selected_nodes.size());
+ auto* enum_variant = new base::win::EnumVariant(selected_count);
+ enum_variant->AddRef();
+ for (LONG i = 0; i < selected_count; ++i) {
+ enum_variant->ItemAt(i)->vt = VT_DISPATCH;
+ enum_variant->ItemAt(i)->pdispVal = selected_nodes[i].Detach();
}
selected->vt = VT_UNKNOWN;
HRESULT hr = enum_variant->QueryInterface(IID_PPV_ARGS(&V_UNKNOWN(selected)));
@@ -1280,8 +1253,8 @@ IFACEMETHODIMP AXPlatformNodeWin::get_groupPosition(
AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
*group_level = GetIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel);
- *similar_items_in_group = GetIntAttribute(ax::mojom::IntAttribute::kSetSize);
- *position_in_group = GetIntAttribute(ax::mojom::IntAttribute::kPosInSet);
+ *similar_items_in_group = GetSetSize();
+ *position_in_group = GetPosInSet();
if (!*group_level && !*similar_items_in_group && !*position_in_group)
return S_FALSE;
@@ -1435,6 +1408,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetIAccessiblePair(IAccessible** accessible,
//
IFACEMETHODIMP AXPlatformNodeWin::Collapse() {
+ UIA_VALIDATE_CALL();
AXActionData action_data;
action_data.action = ax::mojom::Action::kDoDefault;
@@ -1444,6 +1418,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Collapse() {
}
IFACEMETHODIMP AXPlatformNodeWin::Expand() {
+ UIA_VALIDATE_CALL();
AXActionData action_data;
action_data.action = ax::mojom::Action::kDoDefault;
@@ -1454,7 +1429,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Expand() {
IFACEMETHODIMP AXPlatformNodeWin::get_ExpandCollapseState(
ExpandCollapseState* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
const AXNodeData& data = GetData();
if (data.HasState(ax::mojom::State::kExpanded)) {
*result = ExpandCollapseState_Expanded;
@@ -1472,20 +1447,20 @@ IFACEMETHODIMP AXPlatformNodeWin::get_ExpandCollapseState(
//
IFACEMETHODIMP AXPlatformNodeWin::get_Column(int* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = GetTableColumn();
return S_OK;
}
IFACEMETHODIMP AXPlatformNodeWin::get_ColumnSpan(int* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = GetTableColumnSpan();
return S_OK;
}
IFACEMETHODIMP AXPlatformNodeWin::get_ContainingGrid(
IRawElementProviderSimple** result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
AXPlatformNodeBase* table = GetTable();
if (!table)
@@ -1498,13 +1473,13 @@ IFACEMETHODIMP AXPlatformNodeWin::get_ContainingGrid(
}
IFACEMETHODIMP AXPlatformNodeWin::get_Row(int* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = GetTableRow();
return S_OK;
}
IFACEMETHODIMP AXPlatformNodeWin::get_RowSpan(int* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = GetTableRowSpan();
return S_OK;
}
@@ -1516,7 +1491,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_RowSpan(int* result) {
IFACEMETHODIMP AXPlatformNodeWin::GetItem(int row,
int column,
IRawElementProviderSimple** result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
AXPlatformNodeBase* cell = GetTableCell(row, column);
if (!cell)
@@ -1529,13 +1504,13 @@ IFACEMETHODIMP AXPlatformNodeWin::GetItem(int row,
}
IFACEMETHODIMP AXPlatformNodeWin::get_RowCount(int* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = GetTableRowCount();
return S_OK;
}
IFACEMETHODIMP AXPlatformNodeWin::get_ColumnCount(int* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = GetTableColumnCount();
return S_OK;
}
@@ -1545,7 +1520,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_ColumnCount(int* result) {
//
IFACEMETHODIMP AXPlatformNodeWin::ScrollIntoView() {
- COM_OBJECT_VALIDATE();
+ UIA_VALIDATE_CALL();
gfx::Rect r = gfx::ToEnclosingRect(GetData().relative_bounds.bounds);
r -= r.OffsetFromOrigin();
@@ -1564,7 +1539,7 @@ IFACEMETHODIMP AXPlatformNodeWin::ScrollIntoView() {
IFACEMETHODIMP AXPlatformNodeWin::Scroll(ScrollAmount horizontal_amount,
ScrollAmount vertical_amount) {
- COM_OBJECT_VALIDATE();
+ UIA_VALIDATE_CALL();
if (!IsScrollable())
return E_FAIL;
@@ -1580,7 +1555,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Scroll(ScrollAmount horizontal_amount,
IFACEMETHODIMP AXPlatformNodeWin::SetScrollPercent(double horizontal_percent,
double vertical_percent) {
- COM_OBJECT_VALIDATE();
+ UIA_VALIDATE_CALL();
if (!IsScrollable())
return E_FAIL;
@@ -1602,13 +1577,13 @@ IFACEMETHODIMP AXPlatformNodeWin::SetScrollPercent(double horizontal_percent,
}
IFACEMETHODIMP AXPlatformNodeWin::get_HorizontallyScrollable(BOOL* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = IsHorizontallyScrollable();
return S_OK;
}
IFACEMETHODIMP AXPlatformNodeWin::get_HorizontalScrollPercent(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!IsHorizontallyScrollable()) {
*result = UIA_ScrollPatternNoScroll;
return S_OK;
@@ -1624,7 +1599,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_HorizontalScrollPercent(double* result) {
// Horizontal size of the viewable region as a percentage of the total content
// area.
IFACEMETHODIMP AXPlatformNodeWin::get_HorizontalViewSize(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!IsHorizontallyScrollable()) {
*result = 100.;
return S_OK;
@@ -1640,13 +1615,13 @@ IFACEMETHODIMP AXPlatformNodeWin::get_HorizontalViewSize(double* result) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_VerticallyScrollable(BOOL* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = IsVerticallyScrollable();
return S_OK;
}
IFACEMETHODIMP AXPlatformNodeWin::get_VerticalScrollPercent(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!IsVerticallyScrollable()) {
*result = UIA_ScrollPatternNoScroll;
return S_OK;
@@ -1662,7 +1637,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_VerticalScrollPercent(double* result) {
// Vertical size of the viewable region as a percentage of the total content
// area.
IFACEMETHODIMP AXPlatformNodeWin::get_VerticalViewSize(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!IsVerticallyScrollable()) {
*result = 100.0;
return S_OK;
@@ -1682,6 +1657,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_VerticalViewSize(double* result) {
//
IFACEMETHODIMP AXPlatformNodeWin::AddToSelection() {
+ UIA_VALIDATE_CALL();
if (!IsUIASelectable(GetData().role))
return E_FAIL;
@@ -1699,10 +1675,12 @@ IFACEMETHODIMP AXPlatformNodeWin::AddToSelection() {
}
IFACEMETHODIMP AXPlatformNodeWin::RemoveFromSelection() {
+ UIA_VALIDATE_CALL();
return E_NOTIMPL;
}
IFACEMETHODIMP AXPlatformNodeWin::Select() {
+ UIA_VALIDATE_CALL();
if (!IsUIASelectable(GetData().role))
return E_FAIL;
@@ -1720,7 +1698,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Select() {
}
IFACEMETHODIMP AXPlatformNodeWin::get_IsSelected(BOOL* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!IsUIASelectable(GetData().role))
return E_FAIL;
@@ -1735,7 +1713,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_IsSelected(BOOL* result) {
IFACEMETHODIMP AXPlatformNodeWin::get_SelectionContainer(
IRawElementProviderSimple** result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
auto* node_win = static_cast<AXPlatformNodeWin*>(GetSelectionContainer());
if (!node_win)
@@ -1751,7 +1729,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_SelectionContainer(
//
IFACEMETHODIMP AXPlatformNodeWin::GetSelection(SAFEARRAY** result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
int child_count = GetDelegate()->GetChildCount();
*result = SafeArrayCreateVector(VT_UNKNOWN, 0, child_count);
for (LONG i = 0; i < child_count; ++i) {
@@ -1766,12 +1744,13 @@ IFACEMETHODIMP AXPlatformNodeWin::GetSelection(SAFEARRAY** result) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_CanSelectMultiple(BOOL* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
*result = GetData().HasState(ax::mojom::State::kMultiselectable);
return S_OK;
}
IFACEMETHODIMP AXPlatformNodeWin::get_IsSelectionRequired(BOOL* result) {
+ UIA_VALIDATE_CALL_1_ARG(result);
return E_NOTIMPL;
}
@@ -1780,7 +1759,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_IsSelectionRequired(BOOL* result) {
//
IFACEMETHODIMP AXPlatformNodeWin::GetColumnHeaderItems(SAFEARRAY** result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!IsCellOrTableHeader(GetData().role) || !GetTable())
return E_FAIL;
@@ -1794,7 +1773,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetColumnHeaderItems(SAFEARRAY** result) {
}
IFACEMETHODIMP AXPlatformNodeWin::GetRowHeaderItems(SAFEARRAY** result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!IsCellOrTableHeader(GetData().role) || !GetTable())
return E_FAIL;
@@ -1812,7 +1791,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetRowHeaderItems(SAFEARRAY** result) {
//
IFACEMETHODIMP AXPlatformNodeWin::GetColumnHeaders(SAFEARRAY** result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!GetTable())
return E_FAIL;
@@ -1823,7 +1802,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetColumnHeaders(SAFEARRAY** result) {
}
IFACEMETHODIMP AXPlatformNodeWin::GetRowHeaders(SAFEARRAY** result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (!GetTable())
return E_FAIL;
@@ -1835,7 +1814,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetRowHeaders(SAFEARRAY** result) {
IFACEMETHODIMP AXPlatformNodeWin::get_RowOrColumnMajor(
RowOrColumnMajor* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
return E_NOTIMPL;
}
@@ -1844,6 +1823,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_RowOrColumnMajor(
//
IFACEMETHODIMP AXPlatformNodeWin::Toggle() {
+ UIA_VALIDATE_CALL();
AXActionData action_data;
action_data.action = ax::mojom::Action::kDoDefault;
@@ -1853,7 +1833,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Toggle() {
}
IFACEMETHODIMP AXPlatformNodeWin::get_ToggleState(ToggleState* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
const auto checked_state = GetData().GetCheckedState();
if (checked_state == ax::mojom::CheckedState::kTrue) {
*result = ToggleState_On;
@@ -1870,6 +1850,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_ToggleState(ToggleState* result) {
//
IFACEMETHODIMP AXPlatformNodeWin::SetValue(LPCWSTR value) {
+ UIA_VALIDATE_CALL();
if (!value)
return E_INVALIDARG;
@@ -1882,7 +1863,7 @@ IFACEMETHODIMP AXPlatformNodeWin::SetValue(LPCWSTR value) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_IsReadOnly(BOOL* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
int restriction;
if (GetIntAttribute(ax::mojom::IntAttribute::kRestriction, &restriction)) {
*result = static_cast<ax::mojom::Restriction>(restriction) ==
@@ -1893,7 +1874,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_IsReadOnly(BOOL* result) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_Value(BSTR* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
if (GetStringAttributeAsBstr(ax::mojom::StringAttribute::kValue, result))
return S_OK;
return E_FAIL;
@@ -1904,6 +1885,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_Value(BSTR* result) {
//
IFACEMETHODIMP AXPlatformNodeWin::SetValue(double value) {
+ UIA_VALIDATE_CALL();
AXActionData data;
data.action = ax::mojom::Action::kSetValue;
data.value = base::NumberToString(value);
@@ -1913,7 +1895,7 @@ IFACEMETHODIMP AXPlatformNodeWin::SetValue(double value) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_LargeChange(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
float attribute;
if (GetFloatAttribute(ax::mojom::FloatAttribute::kStepValueForRange,
&attribute)) {
@@ -1924,7 +1906,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_LargeChange(double* result) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_Maximum(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
float attribute;
if (GetFloatAttribute(ax::mojom::FloatAttribute::kMaxValueForRange,
&attribute)) {
@@ -1935,7 +1917,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_Maximum(double* result) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_Minimum(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
float attribute;
if (GetFloatAttribute(ax::mojom::FloatAttribute::kMinValueForRange,
&attribute)) {
@@ -1946,7 +1928,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_Minimum(double* result) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_SmallChange(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
float attribute;
if (GetFloatAttribute(ax::mojom::FloatAttribute::kStepValueForRange,
&attribute)) {
@@ -1957,7 +1939,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_SmallChange(double* result) {
}
IFACEMETHODIMP AXPlatformNodeWin::get_Value(double* result) {
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
float attribute;
if (GetFloatAttribute(ax::mojom::FloatAttribute::kValueForRange,
&attribute)) {
@@ -3115,7 +3097,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_attributes(LONG offset,
IFACEMETHODIMP AXPlatformNodeWin::GetPatternProvider(PATTERNID pattern_id,
IUnknown** result) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PATTERN_PROVIDER);
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
const AXNodeData& data = GetData();
@@ -3240,7 +3222,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPatternProvider(PATTERNID pattern_id,
IFACEMETHODIMP AXPlatformNodeWin::GetPropertyValue(PROPERTYID property_id,
VARIANT* result) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PROPERTY_VALUE);
- COM_OBJECT_VALIDATE_1_ARG(result);
+ UIA_VALIDATE_CALL_1_ARG(result);
const AXNodeData& data = GetData();
int int_attribute;
@@ -3315,17 +3297,21 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPropertyValue(PROPERTYID property_id,
if (GetIntAttribute(ax::mojom::IntAttribute::kInvalidState,
&int_attribute)) {
result->vt = VT_BOOL;
- result->boolVal = int_attribute ==
- static_cast<int32_t>(ax::mojom::InvalidState::kFalse);
+ if (int_attribute ==
+ static_cast<int32_t>(ax::mojom::InvalidState::kFalse)) {
+ result->boolVal = VARIANT_TRUE;
+ } else {
+ result->boolVal = VARIANT_FALSE;
+ }
}
break;
case UIA_IsRequiredForFormPropertyId:
result->vt = VT_BOOL;
if (data.HasState(ax::mojom::State::kRequired)) {
- result->boolVal = true;
+ result->boolVal = VARIANT_TRUE;
} else {
- result->boolVal = false;
+ result->boolVal = VARIANT_FALSE;
}
break;
@@ -3355,6 +3341,9 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPropertyValue(PROPERTYID property_id,
result->vt = VT_I4;
result->intVal = OrientationType_Vertical;
}
+ } else {
+ result->vt = VT_I4;
+ result->intVal = OrientationType_None;
}
break;
@@ -3413,12 +3402,14 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPropertyValue(PROPERTYID property_id,
IFACEMETHODIMP AXPlatformNodeWin::get_ProviderOptions(ProviderOptions* ret) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PROVIDER_OPTIONS);
+ UIA_VALIDATE_CALL_1_ARG(ret);
return E_NOTIMPL;
}
IFACEMETHODIMP AXPlatformNodeWin::get_HostRawElementProvider(
IRawElementProviderSimple** provider) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_HOST_RAW_ELEMENT_PROVIDER);
+ UIA_VALIDATE_CALL_1_ARG(provider);
return E_NOTIMPL;
}
@@ -3710,6 +3701,9 @@ int AXPlatformNodeWin::MSAARole() {
case ax::mojom::Role::kListBoxOption:
return ROLE_SYSTEM_LISTITEM;
+ case ax::mojom::Role::kListGrid:
+ return ROLE_SYSTEM_LIST;
+
case ax::mojom::Role::kListItem:
return ROLE_SYSTEM_LISTITEM;
@@ -4501,15 +4495,18 @@ base::string16 AXPlatformNodeWin::UIAAriaRole() {
case ax::mojom::Role::kList:
return L"list";
- case ax::mojom::Role::kListItem:
- return L"listitem";
-
case ax::mojom::Role::kListBox:
return L"listbox";
case ax::mojom::Role::kListBoxOption:
return L"option";
+ case ax::mojom::Role::kListGrid:
+ return L"listview";
+
+ case ax::mojom::Role::kListItem:
+ return L"listitem";
+
case ax::mojom::Role::kLog:
return L"log";
@@ -5119,15 +5116,18 @@ LONG AXPlatformNodeWin::ComputeUIAControlType() { // NOLINT(runtime/int)
case ax::mojom::Role::kList:
return UIA_ListControlTypeId;
- case ax::mojom::Role::kListItem:
- return UIA_ListItemControlTypeId;
-
case ax::mojom::Role::kListBox:
return UIA_ListControlTypeId;
case ax::mojom::Role::kListBoxOption:
return UIA_ListItemControlTypeId;
+ case ax::mojom::Role::kListGrid:
+ return UIA_DataGridControlTypeId;
+
+ case ax::mojom::Role::kListItem:
+ return UIA_ListItemControlTypeId;
+
case ax::mojom::Role::kLog:
return UIA_GroupControlTypeId;
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.h b/chromium/ui/accessibility/platform/ax_platform_node_win.h
index aa5603e9ae1..130b5c89648 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.h
@@ -273,14 +273,10 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
~AXPlatformNodeWin() override;
- // Return the number of instances of AXPlatformNodeWin, for leak testing.
- static size_t GetInstanceCountForTesting();
-
void Init(AXPlatformNodeDelegate* delegate) override;
// Clear any AXPlatformRelationWin nodes owned by this node.
void ClearOwnRelations();
- static AXPlatformNode* GetFromUniqueId(int32_t unique_id);
// AXPlatformNode overrides.
gfx::NativeViewAccessible GetNativeViewAccessible() override;
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 c1e61563ecc..ca1f0eb3d0d 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -15,6 +15,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/iaccessible2/ia2_api_all.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_platform_node_base.h"
#include "ui/accessibility/platform/ax_platform_node_unittest.h"
#include "ui/accessibility/platform/ax_platform_node_win.h"
#include "ui/accessibility/platform/test_ax_node_wrapper.h"
@@ -34,22 +35,87 @@ ScopedVariant SELF(CHILDID_SELF);
} // namespace
+// Helper macros for testing UIAutomation property values and maintain
+// correct stack tracing and failure causality.
+//
+// WARNING: These aren't intended to be generic EXPECT_BSTR_EQ macros
+// as the logic is specific to extracting and comparing UIA property
+// values.
+#define EXPECT_UIA_VALUE_EQ(node, property_id, expectedVariant) \
+ do { \
+ ScopedVariant actual; \
+ ASSERT_HRESULT_SUCCEEDED( \
+ node->GetPropertyValue(property_id, actual.Receive())); \
+ EXPECT_EQ(0, expectedVariant.Compare(actual)); \
+ } while (false)
+
+#define EXPECT_UIA_BSTR_EQ(node, property_id, expected) \
+ do { \
+ ScopedVariant expectedVariant(expected); \
+ ASSERT_EQ(VT_BSTR, expectedVariant.type()); \
+ ASSERT_NE(nullptr, expectedVariant.ptr()->bstrVal); \
+ ScopedVariant actual; \
+ ASSERT_HRESULT_SUCCEEDED( \
+ node->GetPropertyValue(property_id, actual.Receive())); \
+ ASSERT_EQ(VT_BSTR, actual.type()); \
+ ASSERT_NE(nullptr, actual.ptr()->bstrVal); \
+ EXPECT_STREQ(expectedVariant.ptr()->bstrVal, actual.ptr()->bstrVal); \
+ } while (false)
+
+#define EXPECT_UIA_BOOL_EQ(node, property_id, expected) \
+ do { \
+ ScopedVariant expectedVariant(expected, VT_BOOL); \
+ ASSERT_EQ(VT_BOOL, expectedVariant.type()); \
+ ScopedVariant actual; \
+ ASSERT_HRESULT_SUCCEEDED( \
+ node->GetPropertyValue(property_id, actual.Receive())); \
+ EXPECT_EQ(expectedVariant.ptr()->boolVal, actual.ptr()->boolVal); \
+ } while (false)
+
+#define EXPECT_UIA_INT_EQ(node, property_id, expected) \
+ do { \
+ ScopedVariant expectedVariant(expected, VT_I4); \
+ ASSERT_EQ(VT_I4, expectedVariant.type()); \
+ ScopedVariant actual; \
+ ASSERT_HRESULT_SUCCEEDED( \
+ node->GetPropertyValue(property_id, actual.Receive())); \
+ EXPECT_EQ(expectedVariant.ptr()->intVal, actual.ptr()->intVal); \
+ } while (false)
+
class AXPlatformNodeWinTest : public ui::AXPlatformNodeTest {
public:
AXPlatformNodeWinTest() {}
~AXPlatformNodeWinTest() override {}
- void SetUp() override {
- win::CreateATLModuleIfNeeded();
- }
+ void SetUp() override { win::CreateATLModuleIfNeeded(); }
void TearDown() override {
// Destroy the tree and make sure we're not leaking any objects.
tree_.reset(nullptr);
- ASSERT_EQ(0U, AXPlatformNodeWin::GetInstanceCountForTesting());
+ ASSERT_EQ(0U, AXPlatformNodeBase::GetInstanceCountForTesting());
}
protected:
+ template <typename T>
+ ComPtr<T> QueryInterfaceFromNode(AXNode* node) {
+ const TestAXNodeWrapper* wrapper =
+ TestAXNodeWrapper::GetOrCreate(tree_.get(), node);
+ if (!wrapper)
+ return ComPtr<T>();
+
+ AXPlatformNode* ax_platform_node = wrapper->ax_platform_node();
+ ComPtr<T> result;
+ EXPECT_HRESULT_SUCCEEDED(
+ ax_platform_node->GetNativeViewAccessible()->QueryInterface(__uuidof(T),
+ &result));
+
+ return result;
+ }
+
+ ComPtr<IRawElementProviderSimple> GetRootIRawElementProviderSimple() {
+ return QueryInterfaceFromNode<IRawElementProviderSimple>(GetRootNode());
+ }
+
ComPtr<IAccessible> IAccessibleFromNode(AXNode* node) {
TestAXNodeWrapper* wrapper =
TestAXNodeWrapper::GetOrCreate(tree_.get(), node);
@@ -2275,8 +2341,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetGroupPosition) {
LONG level, similar, position;
EXPECT_EQ(S_OK, iaccessible2->get_groupPosition(&level, &similar, &position));
EXPECT_EQ(1, level);
- EXPECT_EQ(1, similar);
- EXPECT_EQ(1, position);
+ EXPECT_EQ(0, similar);
+ EXPECT_EQ(0, position);
EXPECT_EQ(E_INVALIDARG,
iaccessible2->get_groupPosition(nullptr, nullptr, nullptr));
@@ -2579,4 +2645,202 @@ TEST_F(AXPlatformNodeWinTest,
EXPECT_EQ(2, offset);
}
+TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertySimple) {
+ AXNodeData root;
+ root.SetName("fake name");
+ root.AddStringAttribute(ax::mojom::StringAttribute::kAccessKey, "Ctrl+Q");
+ root.AddStringAttribute(ax::mojom::StringAttribute::kKeyShortcuts, "Alt+F4");
+ root.AddStringAttribute(ax::mojom::StringAttribute::kDescription,
+ "fake description");
+ root.AddStringAttribute(ax::mojom::StringAttribute::kRoleDescription,
+ "role description");
+ root.AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 1);
+ root.AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 2);
+ root.AddIntAttribute(ax::mojom::IntAttribute::kInvalidState, 1);
+ root.role = ax::mojom::Role::kMarquee;
+
+ Init(root);
+
+ ComPtr<IRawElementProviderSimple> root_node =
+ GetRootIRawElementProviderSimple();
+ ScopedVariant uia_id;
+ ASSERT_HRESULT_SUCCEEDED(root_node->GetPropertyValue(
+ UIA_AutomationIdPropertyId, uia_id.Receive()));
+ EXPECT_UIA_BSTR_EQ(root_node, UIA_AutomationIdPropertyId,
+ uia_id.ptr()->bstrVal);
+ EXPECT_UIA_BSTR_EQ(root_node, UIA_AriaRolePropertyId, L"marquee");
+ EXPECT_UIA_BSTR_EQ(root_node, UIA_AriaPropertiesPropertyId,
+ L"expanded=false;multiline=false;multiselectable=false;"
+ L"posinset=1;required=false;setsize=2");
+ EXPECT_UIA_INT_EQ(root_node, UIA_ControlTypePropertyId,
+ int{UIA_TextControlTypeId});
+ EXPECT_UIA_INT_EQ(root_node, UIA_OrientationPropertyId,
+ int{OrientationType_None});
+ EXPECT_UIA_BOOL_EQ(root_node, UIA_IsRequiredForFormPropertyId, false);
+ EXPECT_UIA_BOOL_EQ(root_node, UIA_IsDataValidForFormPropertyId, true);
+}
+
+TEST_F(AXPlatformNodeWinTest, TestUIAErrorHandling) {
+ AXNodeData root;
+ Init(root);
+
+ ComPtr<IRawElementProviderSimple> simple_provider =
+ GetRootIRawElementProviderSimple();
+ ComPtr<IGridItemProvider> grid_item_provider =
+ QueryInterfaceFromNode<IGridItemProvider>(GetRootNode());
+ ComPtr<IGridProvider> grid_provider =
+ QueryInterfaceFromNode<IGridProvider>(GetRootNode());
+ ComPtr<IScrollItemProvider> scroll_item_provider =
+ QueryInterfaceFromNode<IScrollItemProvider>(GetRootNode());
+ ComPtr<IScrollProvider> scroll_provider =
+ QueryInterfaceFromNode<IScrollProvider>(GetRootNode());
+ ComPtr<ISelectionItemProvider> selection_item_provider =
+ QueryInterfaceFromNode<ISelectionItemProvider>(GetRootNode());
+ ComPtr<ISelectionProvider> selection_provider =
+ QueryInterfaceFromNode<ISelectionProvider>(GetRootNode());
+ ComPtr<ITableItemProvider> table_item_provider =
+ QueryInterfaceFromNode<ITableItemProvider>(GetRootNode());
+ ComPtr<ITableProvider> table_provider =
+ QueryInterfaceFromNode<ITableProvider>(GetRootNode());
+ ComPtr<IExpandCollapseProvider> expand_collapse_provider =
+ QueryInterfaceFromNode<IExpandCollapseProvider>(GetRootNode());
+ ComPtr<IToggleProvider> toggle_provider =
+ QueryInterfaceFromNode<IToggleProvider>(GetRootNode());
+ ComPtr<IValueProvider> value_provider =
+ QueryInterfaceFromNode<IValueProvider>(GetRootNode());
+ ComPtr<IRangeValueProvider> range_value_provider =
+ QueryInterfaceFromNode<IRangeValueProvider>(GetRootNode());
+
+ tree_.reset(new AXTree());
+
+ // IGridItemProvider
+ int int_result = 0;
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ grid_item_provider->get_Column(&int_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ grid_item_provider->get_ColumnSpan(&int_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ grid_item_provider->get_Row(&int_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ grid_item_provider->get_RowSpan(&int_result));
+
+ // IExpandCollapseProvider
+ ExpandCollapseState expand_collapse_state;
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ expand_collapse_provider->Collapse());
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ expand_collapse_provider->Expand());
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ expand_collapse_provider->get_ExpandCollapseState(
+ &expand_collapse_state));
+
+ // IGridProvider
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ grid_provider->GetItem(0, 0, simple_provider.GetAddressOf()));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ grid_provider->get_RowCount(&int_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ grid_provider->get_ColumnCount(&int_result));
+
+ // IScrollItemProvider
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ scroll_item_provider->ScrollIntoView());
+
+ // IScrollProvider
+ BOOL bool_result = TRUE;
+ double double_result = 3.14;
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ scroll_provider->SetScrollPercent(0, 0));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ scroll_provider->get_HorizontallyScrollable(&bool_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ scroll_provider->get_HorizontalScrollPercent(&double_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ scroll_provider->get_HorizontalViewSize(&double_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ scroll_provider->get_VerticallyScrollable(&bool_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ scroll_provider->get_VerticalScrollPercent(&double_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ scroll_provider->get_VerticalViewSize(&double_result));
+
+ // ISelectionItemProvider
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ selection_item_provider->AddToSelection());
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ selection_item_provider->RemoveFromSelection());
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ selection_item_provider->Select());
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ selection_item_provider->get_IsSelected(&bool_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ selection_item_provider->get_SelectionContainer(
+ simple_provider.GetAddressOf()));
+
+ // ISelectionProvider
+ SAFEARRAY* array_result = nullptr;
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ selection_provider->GetSelection(&array_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ selection_provider->get_CanSelectMultiple(&bool_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ selection_provider->get_IsSelectionRequired(&bool_result));
+
+ // ITableItemProvider
+ RowOrColumnMajor row_or_column_major_result;
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ table_item_provider->GetColumnHeaderItems(&array_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ table_item_provider->GetRowHeaderItems(&array_result));
+
+ // ITableProvider
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ table_provider->GetColumnHeaders(&array_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ table_provider->GetRowHeaders(&array_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ table_provider->get_RowOrColumnMajor(&row_or_column_major_result));
+
+ // IRawElementProviderSimple
+ ScopedVariant variant;
+ ComPtr<IUnknown> unknown;
+ ProviderOptions options;
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ simple_provider->GetPatternProvider(UIA_WindowPatternId,
+ unknown.GetAddressOf()));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ simple_provider->GetPropertyValue(UIA_FrameworkIdPropertyId,
+ variant.Receive()));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ simple_provider->get_ProviderOptions(&options));
+
+ // IValueProvider
+ ScopedBstr bstr_value;
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ value_provider->SetValue(L"3.14"));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ value_provider->get_Value(bstr_value.Receive()));
+
+ // IRangeValueProvider
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ range_value_provider->SetValue(double_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ range_value_provider->get_LargeChange(&double_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ range_value_provider->get_Maximum(&double_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ range_value_provider->get_Minimum(&double_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ range_value_provider->get_SmallChange(&double_result));
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ range_value_provider->get_Value(&double_result));
+
+ // IToggleProvider
+ ToggleState toggle_state;
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ toggle_provider->Toggle());
+ EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
+ toggle_provider->get_ToggleState(&toggle_state));
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_relation_win.cc b/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
index de7229a7303..165789772ad 100644
--- a/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
@@ -9,7 +9,6 @@
#include <algorithm>
#include <vector>
-#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
diff --git a/chromium/ui/accessibility/platform/compute_attributes.cc b/chromium/ui/accessibility/platform/compute_attributes.cc
new file mode 100644
index 00000000000..1b04e0ebfe4
--- /dev/null
+++ b/chromium/ui/accessibility/platform/compute_attributes.cc
@@ -0,0 +1,127 @@
+// 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/platform/compute_attributes.h"
+
+#include <cstddef>
+
+#include "base/optional.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_platform_node_delegate.h"
+
+namespace ui {
+namespace {
+
+base::Optional<int32_t> GetCellAttribute(
+ const ui::AXPlatformNodeDelegate* delegate,
+ ax::mojom::IntAttribute attribute) {
+ switch (attribute) {
+ case ax::mojom::IntAttribute::kAriaCellColumnIndex:
+ return delegate->GetTableCellAriaColIndex();
+ case ax::mojom::IntAttribute::kAriaCellRowIndex:
+ return delegate->GetTableCellAriaRowIndex();
+ case ax::mojom::IntAttribute::kTableCellColumnIndex:
+ return delegate->GetTableCellColIndex();
+ case ax::mojom::IntAttribute::kTableCellRowIndex:
+ return delegate->GetTableCellRowIndex();
+ case ax::mojom::IntAttribute::kTableCellColumnSpan:
+ return delegate->GetTableCellColSpan();
+ case ax::mojom::IntAttribute::kTableCellRowSpan:
+ return delegate->GetTableCellRowSpan();
+ default:
+ return base::nullopt;
+ }
+}
+
+base::Optional<int32_t> GetRowAttribute(
+ const ui::AXPlatformNodeDelegate* delegate,
+ ax::mojom::IntAttribute attribute) {
+ if (attribute == ax::mojom::IntAttribute::kTableRowIndex) {
+ return delegate->GetTableRowRowIndex();
+ }
+ return base::nullopt;
+}
+
+base::Optional<int32_t> GetTableAttribute(
+ const ui::AXPlatformNodeDelegate* delegate,
+ ax::mojom::IntAttribute attribute) {
+ switch (attribute) {
+ case ax::mojom::IntAttribute::kTableColumnCount:
+ return delegate->GetTableColCount();
+ case ax::mojom::IntAttribute::kTableRowCount:
+ return delegate->GetTableRowCount();
+ case ax::mojom::IntAttribute::kAriaColumnCount:
+ return delegate->GetTableAriaColCount();
+ case ax::mojom::IntAttribute::kAriaRowCount:
+ return delegate->GetTableAriaRowCount();
+ default:
+ return base::nullopt;
+ }
+}
+
+base::Optional<int32_t> GetOrderedSetItemAttribute(
+ const ui::AXPlatformNodeDelegate* delegate,
+ ax::mojom::IntAttribute attribute) {
+ int value = 0;
+ switch (attribute) {
+ case ax::mojom::IntAttribute::kPosInSet:
+ value = delegate->GetPosInSet();
+ return value;
+ case ax::mojom::IntAttribute::kSetSize:
+ value = delegate->GetSetSize();
+ return value;
+ default:
+ return base::nullopt;
+ }
+}
+
+base::Optional<int32_t> GetOrderedSetAttribute(
+ const ui::AXPlatformNodeDelegate* delegate,
+ ax::mojom::IntAttribute attribute) {
+ int value = 0;
+ switch (attribute) {
+ case ax::mojom::IntAttribute::kSetSize:
+ value = delegate->GetSetSize();
+ return value;
+ default:
+ return base::nullopt;
+ }
+}
+
+base::Optional<int32_t> GetFromData(const ui::AXPlatformNodeDelegate* delegate,
+ ax::mojom::IntAttribute attribute) {
+ int32_t value;
+ if (delegate->GetData().GetIntAttribute(attribute, &value)) {
+ return value;
+ }
+ return base::nullopt;
+}
+
+} // namespace
+
+base::Optional<int32_t> ComputeAttribute(
+ const ui::AXPlatformNodeDelegate* delegate,
+ ax::mojom::IntAttribute attribute) {
+ base::Optional<int32_t> maybe_value = base::nullopt;
+ // Table-related nodes.
+ if (delegate->IsTableCellOrHeader())
+ maybe_value = GetCellAttribute(delegate, attribute);
+ else if (delegate->IsTableRow())
+ maybe_value = GetRowAttribute(delegate, attribute);
+ else if (delegate->IsTable())
+ maybe_value = GetTableAttribute(delegate, attribute);
+ // Ordered-set-related nodes.
+ else if (delegate->IsOrderedSetItem())
+ maybe_value = GetOrderedSetItemAttribute(delegate, attribute);
+ else if (delegate->IsOrderedSet())
+ maybe_value = GetOrderedSetAttribute(delegate, attribute);
+
+ if (!maybe_value.has_value()) {
+ return GetFromData(delegate, attribute);
+ }
+ return maybe_value;
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/platform/compute_attributes.h b/chromium/ui/accessibility/platform/compute_attributes.h
new file mode 100644
index 00000000000..3a0eb47055b
--- /dev/null
+++ b/chromium/ui/accessibility/platform/compute_attributes.h
@@ -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.
+
+#ifndef UI_ACCESSIBILITY_PLATFORM_COMPUTE_ATTRIBUTES_H_
+#define UI_ACCESSIBILITY_PLATFORM_COMPUTE_ATTRIBUTES_H_
+
+#include <cstddef>
+
+#include "base/optional.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/platform/ax_platform_node_delegate.h"
+
+namespace ui {
+
+// Compute the attribute value instead of returning the "raw" attribute value
+// for those attributes that have computation methods.
+AX_EXPORT base::Optional<int32_t> ComputeAttribute(
+ const ui::AXPlatformNodeDelegate* delegate,
+ ax::mojom::IntAttribute attribute);
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_PLATFORM_COMPUTE_ATTRIBUTES_H_
diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
index c8481e78cf7..f3462d8f0b3 100644
--- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -4,10 +4,10 @@
#include "ui/accessibility/platform/test_ax_node_wrapper.h"
-#include "base/containers/hash_tables.h"
#include "base/stl_util.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_table_info.h"
+#include "ui/accessibility/ax_tree_observer.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace ui {
@@ -15,20 +15,15 @@ namespace ui {
namespace {
// A global map from AXNodes to TestAXNodeWrappers.
-base::hash_map<AXNode*, TestAXNodeWrapper*> g_node_to_wrapper_map;
+std::unordered_map<AXNode*, TestAXNodeWrapper*> g_node_to_wrapper_map;
// A global coordinate offset.
gfx::Vector2d g_offset;
-// A simple implementation of AXTreeDelegate to catch when AXNodes are
+// A simple implementation of AXTreeObserver to catch when AXNodes are
// deleted so we can delete their wrappers.
-class TestAXTreeDelegate : public AXTreeDelegate {
- void OnNodeDataWillChange(AXTree* tree,
- const AXNodeData& old_node_data,
- const AXNodeData& new_node_data) override {}
- void OnTreeDataChanged(AXTree* tree,
- const AXTreeData& old_data,
- const AXTreeData& new_data) override {}
+class TestAXTreeObserver : public AXTreeObserver {
+ private:
void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override {
auto iter = g_node_to_wrapper_map.find(node);
if (iter != g_node_to_wrapper_map.end()) {
@@ -37,18 +32,9 @@ class TestAXTreeDelegate : public AXTreeDelegate {
g_node_to_wrapper_map.erase(iter->first);
}
}
- void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) override {}
- void OnNodeWillBeReparented(AXTree* tree, AXNode* node) override {}
- void OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) override {}
- void OnNodeCreated(AXTree* tree, AXNode* node) override {}
- void OnNodeReparented(AXTree* tree, AXNode* node) override {}
- void OnNodeChanged(AXTree* tree, AXNode* node) override {}
- void OnAtomicUpdateFinished(AXTree* tree,
- bool root_changed,
- const std::vector<Change>& changes) override {}
};
-TestAXTreeDelegate g_ax_tree_delegate;
+TestAXTreeObserver g_ax_tree_observer;
} // namespace
@@ -57,7 +43,8 @@ TestAXNodeWrapper* TestAXNodeWrapper::GetOrCreate(AXTree* tree, AXNode* node) {
if (!tree || !node)
return nullptr;
- tree->SetDelegate(&g_ax_tree_delegate);
+ if (!tree->HasObserver(&g_ax_tree_observer))
+ tree->AddObserver(&g_ax_tree_observer);
auto iter = g_node_to_wrapper_map.find(node);
if (iter != g_node_to_wrapper_map.end())
return iter->second;
@@ -194,6 +181,19 @@ void TestAXNodeWrapper::ReplaceIntAttribute(int32_t node_id,
node->SetData(new_data);
}
+void TestAXNodeWrapper::ReplaceBoolAttribute(ax::mojom::BoolAttribute attribute,
+ bool value) {
+ AXNodeData new_data = GetData();
+ std::vector<std::pair<ax::mojom::BoolAttribute, bool>>& attributes =
+ new_data.bool_attributes;
+
+ base::EraseIf(attributes,
+ [attribute](auto& pair) { return pair.first == attribute; });
+
+ new_data.AddBoolAttribute(attribute, value);
+ node_->SetData(new_data);
+}
+
int TestAXNodeWrapper::GetTableRowCount() const {
return node_->GetTableRowCount();
}
@@ -261,6 +261,13 @@ bool TestAXNodeWrapper::AccessibilityPerformAction(
return true;
}
+ if (GetData().role == ax::mojom::Role::kListBoxOption &&
+ data.action == ax::mojom::Action::kDoDefault) {
+ bool current_value =
+ GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected);
+ ReplaceBoolAttribute(ax::mojom::BoolAttribute::kSelected, !current_value);
+ }
+
if (data.action == ax::mojom::Action::kSetSelection) {
ReplaceIntAttribute(data.anchor_node_id,
ax::mojom::IntAttribute::kTextSelStart,
@@ -300,4 +307,20 @@ TestAXNodeWrapper::TestAXNodeWrapper(AXTree* tree, AXNode* node)
platform_node_(AXPlatformNode::Create(this)) {
}
+bool TestAXNodeWrapper::IsOrderedSetItem() const {
+ return node_->IsOrderedSetItem();
+}
+
+bool TestAXNodeWrapper::IsOrderedSet() const {
+ return node_->IsOrderedSet();
+}
+
+int32_t TestAXNodeWrapper::GetPosInSet() const {
+ return node_->GetPosInSet();
+}
+
+int32_t TestAXNodeWrapper::GetSetSize() const {
+ return node_->GetSetSize();
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
index 7ac7d2fcf37..ff4fd908399 100644
--- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -17,8 +17,6 @@ namespace ui {
class TestAXNodeWrapper : public AXPlatformNodeDelegateBase {
public:
// Create TestAXNodeWrapper instances on-demand from an AXTree and AXNode.
- // Note that this sets the AXTreeDelegate, you can't use this class if
- // you also want to implement AXTreeDelegate.
static TestAXNodeWrapper* GetOrCreate(AXTree* tree, AXNode* node);
// Set a global coordinate offset for testing.
@@ -26,7 +24,7 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegateBase {
~TestAXNodeWrapper() override;
- AXPlatformNode* ax_platform_node() { return platform_node_; }
+ AXPlatformNode* ax_platform_node() const { return platform_node_; }
void BuildAllWrappers(AXTree* tree, AXNode* node);
@@ -59,12 +57,17 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegateBase {
int32_t dst_id) override;
std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr,
int32_t dst_id) override;
+ bool IsOrderedSetItem() const override;
+ bool IsOrderedSet() const override;
+ int32_t GetPosInSet() const override;
+ int32_t GetSetSize() const override;
private:
TestAXNodeWrapper(AXTree* tree, AXNode* node);
void ReplaceIntAttribute(int32_t node_id,
ax::mojom::IntAttribute attribute,
int32_t value);
+ void ReplaceBoolAttribute(ax::mojom::BoolAttribute attribute, bool value);
TestAXNodeWrapper* HitTestSyncInternal(int x, int y);
diff --git a/chromium/ui/android/BUILD.gn b/chromium/ui/android/BUILD.gn
index aedd969fc22..62af292b248 100644
--- a/chromium/ui/android/BUILD.gn
+++ b/chromium/ui/android/BUILD.gn
@@ -2,12 +2,20 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/buildflag_header.gni")
import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
import("//testing/test.gni")
+import("//ui/android/features.gni")
assert(is_android)
+# Generate a buildflag header for compile-time checking of android night mode support.
+buildflag_header("buildflags") {
+ header = "buildflags.h"
+ flags = [ "ENABLE_ANDROID_NIGHT_MODE=$enable_android_night_mode" ]
+}
+
component("android") {
output_name = "ui_android"
sources = [
@@ -55,6 +63,7 @@ component("android") {
defines = [ "UI_ANDROID_IMPLEMENTATION" ]
deps = [
+ ":buildflags",
":java_enums_srcjar",
":ui_android_jni_headers",
"//base",
@@ -168,55 +177,15 @@ java_strings_grd("ui_strings_grd") {
]
}
-# Generate an Android resources target that contains localized strings
-# describing the current locale used by the Android framework to display
-# UI strings. These are used by org.chromium.ui.base.LocalizationUtils.
-#
-# Variables:
-# ui_locales: List of Chromium locale names to generate resources for.
-#
-template("generate_ui_locale_resources") {
- _generating_target_name = "${target_name}__generate"
- _rebased_output_zip_path = rebase_path(target_gen_dir, root_gen_dir)
- _output_zip = "${root_out_dir}/resource_zips/${_rebased_output_zip_path}/" +
- "${target_name}.zip"
-
- _locales = invoker.ui_locales
- _depfile = "$target_gen_dir/$target_name.d"
-
- action(_generating_target_name) {
- script = "build/create_ui_locale_resources.py"
- depfile = _depfile
- outputs = [
- _output_zip,
- ]
- args = [
- "--locale-list=$_locales",
- "--depfile",
- rebase_path(_depfile, root_build_dir),
- "--output-zip",
- rebase_path(_output_zip, root_build_dir),
- ]
- }
-
- android_generated_resources(target_name) {
- generating_target_name = ":$_generating_target_name"
- generated_resources_zip = _output_zip
- }
-}
-
-generate_ui_locale_resources("ui_locale_string_resources") {
- # NOTE: It is not possible to pass just |locales| here, otherwise
- # the lint step will later complain that 3 strings in android_ui_strings.grd
- # are not localized to the omitted locales!
- ui_locales = locales - android_chrome_omitted_locales
-}
-
android_resources("ui_java_resources") {
custom_package = "org.chromium.ui"
resource_dirs = [ "java/res" ]
+
+ if (enable_android_night_mode) {
+ resource_dirs += [ "//ui/android/java/res_night" ]
+ }
+
deps = [
- ":ui_locale_string_resources",
":ui_strings_grd",
]
}
@@ -289,6 +258,26 @@ android_library("ui_full_java") {
"java/src/org/chromium/ui/gl/SurfaceTextureListener.java",
"java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java",
"java/src/org/chromium/ui/interpolators/BakedBezierInterpolator.java",
+ "java/src/org/chromium/ui/modaldialog/DialogDismissalCause.java",
+ "java/src/org/chromium/ui/modaldialog/ModalDialogManager.java",
+ "java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java",
+ "java/src/org/chromium/ui/modelutil/ForwardingListObservable.java",
+ "java/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcp.java",
+ "java/src/org/chromium/ui/modelutil/ListModel.java",
+ "java/src/org/chromium/ui/modelutil/ListModelBase.java",
+ "java/src/org/chromium/ui/modelutil/ListModelChangeProcessor.java",
+ "java/src/org/chromium/ui/modelutil/ListObservable.java",
+ "java/src/org/chromium/ui/modelutil/ListObservableImpl.java",
+ "java/src/org/chromium/ui/modelutil/ModelListAdapter.java",
+ "java/src/org/chromium/ui/modelutil/PropertyKey.java",
+ "java/src/org/chromium/ui/modelutil/PropertyListModel.java",
+ "java/src/org/chromium/ui/modelutil/PropertyModel.java",
+ "java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java",
+ "java/src/org/chromium/ui/modelutil/PropertyObservable.java",
+ "java/src/org/chromium/ui/modelutil/RecyclerViewAdapter.java",
+ "java/src/org/chromium/ui/modelutil/SimpleList.java",
+ "java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcp.java",
+ "java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcpBase.java",
"java/src/org/chromium/ui/resources/HandleViewResources.java",
"java/src/org/chromium/ui/resources/LayoutResource.java",
"java/src/org/chromium/ui/resources/Resource.java",
@@ -311,6 +300,7 @@ android_library("ui_full_java") {
"java/src/org/chromium/ui/widget/AnchoredPopupWindow.java",
"java/src/org/chromium/ui/widget/ButtonCompat.java",
"java/src/org/chromium/ui/widget/CheckableImageView.java",
+ "java/src/org/chromium/ui/widget/ChipView.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",
@@ -330,6 +320,7 @@ android_library("ui_full_java") {
"//base:base_java",
"//third_party/android_deps:android_support_annotations_java",
"//third_party/android_deps:android_support_v7_appcompat_java",
+ "//third_party/android_deps:android_support_v7_recyclerview_java",
]
srcjar_deps = [
":java_enums_srcjar",
@@ -344,11 +335,13 @@ android_library("ui_java_test_support") {
"javatests/src/org/chromium/ui/test/util/UiDisableIfSkipCheck.java",
"javatests/src/org/chromium/ui/test/util/UiRestriction.java",
"javatests/src/org/chromium/ui/test/util/UiRestrictionSkipCheck.java",
+ "javatests/src/org/chromium/ui/test/util/modelutil/FakeViewProvider.java",
]
deps = [
":ui_java",
"//base:base_java",
"//base:base_java_test_support",
+ "//third_party/junit",
]
}
@@ -366,6 +359,10 @@ junit_binary("ui_junit_tests") {
"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/modaldialog/ModalDialogManagerTest.java",
+ "junit/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcpTest.java",
+ "junit/src/org/chromium/ui/modelutil/PropertyModelTest.java",
+ "junit/src/org/chromium/ui/modelutil/SimpleListObservableTest.java",
"junit/src/org/chromium/ui/text/SpanApplierTest.java",
"junit/src/org/chromium/ui/shadows/ShadowAsyncLayoutInflater.java",
"junit/src/org/chromium/ui/shadows/ShadowAppCompatResources.java",
@@ -375,6 +372,7 @@ junit_binary("ui_junit_tests") {
]
deps = [
":ui_java",
+ ":ui_java_test_support",
":ui_javatest_resources",
"//base:base_java",
"//base:base_java_test_support",
diff --git a/chromium/ui/android/build/create_ui_locale_resources.py b/chromium/ui/android/build/create_ui_locale_resources.py
deleted file mode 100755
index 62943353f1d..00000000000
--- a/chromium/ui/android/build/create_ui_locale_resources.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-#
-# 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.
-
-"""Generate a zip archive containing localized locale name Android resource
-strings!
-
-This script takes a list of input Chrome-specific locale names, as well as an
-output zip file path.
-
-Each output file will contain the definition of a single string resource,
-named 'current_locale', whose value will be the matching Chromium locale name.
-E.g. values-en-rUS/strings.xml will define 'current_locale' as 'en-US'.
-"""
-
-import argparse
-import os
-import sys
-import zipfile
-
-sys.path.insert(0, os.path.join(
- os.path.dirname(__file__), '..', '..', '..', 'build', 'android', 'gyp'))
-
-from util import build_utils
-from util import resource_utils
-
-# A small string template for the content of each strings.xml file.
-# NOTE: The name is chosen to avoid any conflicts with other string defined
-# by other resource archives.
-_TEMPLATE = """\
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string name="current_detected_ui_locale_name">{resource_text}</string>
-</resources>
-"""
-
-# The default Chrome locale value.
-_DEFAULT_CHROME_LOCALE = 'en-US'
-
-
-def _GenerateLocaleStringsXml(locale):
- return _TEMPLATE.format(resource_text=locale)
-
-
-def _AddLocaleResourceFileToZip(out_zip, android_locale, locale):
- locale_data = _GenerateLocaleStringsXml(locale)
- if android_locale:
- zip_path = 'values-%s/strings.xml' % android_locale
- else:
- zip_path = 'values/strings.xml'
- build_utils.AddToZipHermetic(out_zip, zip_path, data=locale_data,
- compress=False)
-
-
-def main():
- parser = argparse.ArgumentParser(
- description=__doc__,
- formatter_class=argparse.RawDescriptionHelpFormatter)
-
- build_utils.AddDepfileOption(parser)
- parser.add_argument('--locale-list', required=True,
- help='GN-list of Chrome-specific locale names.')
- parser.add_argument('--output-zip', required=True,
- help='Output zip archive path.')
-
- args = parser.parse_args()
-
- locale_list = build_utils.ParseGnList(args.locale_list)
- if not locale_list:
- raise Exception('Locale list cannot be empty!')
-
- with build_utils.AtomicOutput(args.output_zip) as tmp_file:
- with zipfile.ZipFile(tmp_file, 'w') as out_zip:
- # First, write the default value, since aapt requires one.
- _AddLocaleResourceFileToZip(out_zip, '', _DEFAULT_CHROME_LOCALE)
-
- for locale in locale_list:
- android_locale = \
- resource_utils.CHROME_TO_ANDROID_LOCALE_MAP.get(locale, locale)
- _AddLocaleResourceFileToZip(out_zip, android_locale, locale)
-
- if args.depfile:
- build_utils.WriteDepfile(args.depfile, args.output_zip)
-
-if __name__ == '__main__':
- main()
diff --git a/chromium/ui/android/delegated_frame_host_android_unittest.cc b/chromium/ui/android/delegated_frame_host_android_unittest.cc
index 2a52e65add4..994438f3af1 100644
--- a/chromium/ui/android/delegated_frame_host_android_unittest.cc
+++ b/chromium/ui/android/delegated_frame_host_android_unittest.cc
@@ -4,11 +4,13 @@
#include "ui/android/delegated_frame_host_android.h"
#include "base/android/build_info.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/test_mock_time_task_runner.h"
#include "cc/layers/layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/surface_layer.h"
#include "cc/trees/layer_tree_host.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/host/host_frame_sink_manager.h"
@@ -87,13 +89,11 @@ class DelegatedFrameHostAndroidTest : public testing::Test {
view_.SetLayer(cc::SolidColorLayer::Create());
frame_host_ = std::make_unique<DelegatedFrameHostAndroid>(
&view_, &host_frame_sink_manager_, &client_, frame_sink_id_,
- ShouldEnableSurfaceSynchronization());
+ features::IsSurfaceSynchronizationEnabled());
}
void TearDown() override { frame_host_.reset(); }
- virtual bool ShouldEnableSurfaceSynchronization() const { return false; }
-
ui::CompositorLock* GetLock(CompositorLockClient* client,
base::TimeDelta time_delta) {
return lock_manager_.GetCompositorLock(client, time_delta, nullptr)
@@ -139,13 +139,63 @@ class DelegatedFrameHostAndroidTest : public testing::Test {
CompositorLockManager lock_manager_;
};
-class DelegatedFrameHostAndroidSurfaceSynchronizationTest
+class DelegatedFrameHostAndroidVizTest : public DelegatedFrameHostAndroidTest {
+ public:
+ DelegatedFrameHostAndroidVizTest() = default;
+ ~DelegatedFrameHostAndroidVizTest() override = default;
+
+ void SetUp() override {
+ // Enable both Viz and SurfaceSync.
+ scoped_feature_list_.InitWithFeatures(
+ {features::kVizDisplayCompositor,
+ features::kEnableSurfaceSynchronization},
+ {});
+
+ DelegatedFrameHostAndroidTest::SetUp();
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// TODO(ericrk): Remove these tests once Viz OOP-D has launched.
+class DelegatedFrameHostAndroidSurfaceSynchronizationOnlyTest
+ : public DelegatedFrameHostAndroidTest {
+ public:
+ DelegatedFrameHostAndroidSurfaceSynchronizationOnlyTest() = default;
+ ~DelegatedFrameHostAndroidSurfaceSynchronizationOnlyTest() override = default;
+
+ void SetUp() override {
+ // Enable SurfaceSync without Viz.
+ scoped_feature_list_.InitWithFeatures(
+ {features::kEnableSurfaceSynchronization},
+ {features::kVizDisplayCompositor});
+
+ DelegatedFrameHostAndroidTest::SetUp();
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// TODO(ericrk): Remove these tests once Viz OOP-D has launched.
+class DelegatedFrameHostAndroidLegacyNonVizTest
: public DelegatedFrameHostAndroidTest {
public:
- DelegatedFrameHostAndroidSurfaceSynchronizationTest() = default;
- ~DelegatedFrameHostAndroidSurfaceSynchronizationTest() override = default;
+ DelegatedFrameHostAndroidLegacyNonVizTest() = default;
+ ~DelegatedFrameHostAndroidLegacyNonVizTest() override = default;
+
+ void SetUp() override {
+ // Disable both Viz and SurfaceSync.
+ scoped_feature_list_.InitWithFeatures(
+ {}, {features::kVizDisplayCompositor,
+ features::kEnableSurfaceSynchronization});
+
+ DelegatedFrameHostAndroidTest::SetUp();
+ }
- bool ShouldEnableSurfaceSynchronization() const override { return true; }
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
};
// Resize lock is only enabled on O+.
@@ -154,10 +204,9 @@ static bool IsResizeLockEnabled() {
base::android::SDK_VERSION_OREO;
}
-// If surface synchronization is enabled then we should not be acquiring a
-// compositor lock on attach.
-TEST_F(DelegatedFrameHostAndroidSurfaceSynchronizationTest,
- NoCompositorLockOnAttach) {
+// If OOP-D is enabled then we should not be acquiring a compositor lock on
+// attach.
+TEST_F(DelegatedFrameHostAndroidVizTest, NoCompositorLockOnAttach) {
EXPECT_CALL(compositor_, IsDrawingFirstVisibleFrame()).Times(0);
EXPECT_CALL(compositor_, DoGetCompositorLock(_, _)).Times(0);
frame_host_->AttachToCompositor(&compositor_);
@@ -166,7 +215,8 @@ TEST_F(DelegatedFrameHostAndroidSurfaceSynchronizationTest,
// If surface synchronization is off, and we are doing a cross-process
// navigation, then both the primary and fallback surface IDs need to be
// updated together.
-TEST_F(DelegatedFrameHostAndroidTest, TakeFallbackContentFromUpdatesPrimary) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest,
+ TakeFallbackContentFromUpdatesPrimary) {
EXPECT_FALSE(frame_host_->SurfaceId().is_valid());
// Submit a compositor frame to ensure we have delegated content.
SubmitCompositorFrame();
@@ -175,7 +225,7 @@ TEST_F(DelegatedFrameHostAndroidTest, TakeFallbackContentFromUpdatesPrimary) {
std::unique_ptr<DelegatedFrameHostAndroid> other_frame_host =
std::make_unique<DelegatedFrameHostAndroid>(
&view_, &host_frame_sink_manager_, &client_, viz::FrameSinkId(2, 2),
- ShouldEnableSurfaceSynchronization());
+ features::IsSurfaceSynchronizationEnabled());
EXPECT_FALSE(other_frame_host->SurfaceId().is_valid());
@@ -187,7 +237,8 @@ TEST_F(DelegatedFrameHostAndroidTest, TakeFallbackContentFromUpdatesPrimary) {
->oldest_acceptable_fallback());
}
-TEST_F(DelegatedFrameHostAndroidTest, CompositorLockDuringFirstFrame) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest,
+ CompositorLockDuringFirstFrame) {
// Attach during the first frame, lock will be taken.
EXPECT_CALL(compositor_, IsDrawingFirstVisibleFrame()).WillOnce(Return(true));
EXPECT_CALL(compositor_, DoGetCompositorLock(frame_host_.get(), _))
@@ -200,7 +251,8 @@ TEST_F(DelegatedFrameHostAndroidTest, CompositorLockDuringFirstFrame) {
EXPECT_FALSE(IsLocked());
}
-TEST_F(DelegatedFrameHostAndroidTest, CompositorLockDuringLaterFrame) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest,
+ CompositorLockDuringLaterFrame) {
// Attach after the first frame, lock will not be taken.
EXPECT_CALL(compositor_, IsDrawingFirstVisibleFrame())
.WillOnce(Return(false));
@@ -208,7 +260,8 @@ TEST_F(DelegatedFrameHostAndroidTest, CompositorLockDuringLaterFrame) {
frame_host_->AttachToCompositor(&compositor_);
}
-TEST_F(DelegatedFrameHostAndroidTest, CompositorLockWithDelegatedContent) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest,
+ CompositorLockWithDelegatedContent) {
// Submit a compositor frame to ensure we have delegated content.
SubmitCompositorFrame();
@@ -219,7 +272,8 @@ TEST_F(DelegatedFrameHostAndroidTest, CompositorLockWithDelegatedContent) {
frame_host_->AttachToCompositor(&compositor_);
}
-TEST_F(DelegatedFrameHostAndroidTest, CompositorLockReleasedWithDetach) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest,
+ CompositorLockReleasedWithDetach) {
// Attach during the first frame, lock will be taken.
EXPECT_CALL(compositor_, IsDrawingFirstVisibleFrame()).WillOnce(Return(true));
EXPECT_CALL(compositor_, DoGetCompositorLock(frame_host_.get(), _))
@@ -232,7 +286,7 @@ TEST_F(DelegatedFrameHostAndroidTest, CompositorLockReleasedWithDetach) {
EXPECT_FALSE(IsLocked());
}
-TEST_F(DelegatedFrameHostAndroidTest, ResizeLockBasic) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest, ResizeLockBasic) {
// Resize lock is only enabled on O+.
if (!IsResizeLockEnabled())
return;
@@ -254,7 +308,8 @@ TEST_F(DelegatedFrameHostAndroidTest, ResizeLockBasic) {
EXPECT_FALSE(IsLocked());
}
-TEST_F(DelegatedFrameHostAndroidTest, ResizeLockNotTakenIfNoSizeChange) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest,
+ ResizeLockNotTakenIfNoSizeChange) {
// Resize lock is only enabled on O+.
if (!IsResizeLockEnabled())
return;
@@ -266,7 +321,8 @@ TEST_F(DelegatedFrameHostAndroidTest, ResizeLockNotTakenIfNoSizeChange) {
EXPECT_FALSE(IsLocked());
}
-TEST_F(DelegatedFrameHostAndroidTest, ResizeLockReleasedWithDetach) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest,
+ ResizeLockReleasedWithDetach) {
// Resize lock is only enabled on O+.
if (!IsResizeLockEnabled())
return;
@@ -284,7 +340,7 @@ TEST_F(DelegatedFrameHostAndroidTest, ResizeLockReleasedWithDetach) {
EXPECT_FALSE(IsLocked());
}
-TEST_F(DelegatedFrameHostAndroidTest, TestBothCompositorLocks) {
+TEST_F(DelegatedFrameHostAndroidLegacyNonVizTest, TestBothCompositorLocks) {
// Resize lock is only enabled on O+.
if (!IsResizeLockEnabled())
return;
@@ -309,7 +365,7 @@ TEST_F(DelegatedFrameHostAndroidTest, TestBothCompositorLocks) {
// Make sure frame evictor is notified of the newly embedded surface after
// WasShown.
-TEST_F(DelegatedFrameHostAndroidSurfaceSynchronizationTest, EmbedWhileHidden) {
+TEST_F(DelegatedFrameHostAndroidVizTest, EmbedWhileHidden) {
{
EXPECT_CALL(client_, WasEvicted());
frame_host_->EvictDelegatedFrame();
@@ -329,7 +385,7 @@ TEST_F(DelegatedFrameHostAndroidSurfaceSynchronizationTest, EmbedWhileHidden) {
// 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,
+TEST_F(DelegatedFrameHostAndroidSurfaceSynchronizationOnlyTest,
FullSurfaceCapture) {
// First embed a surface to make sure we have something to copy from.
allocator_.GenerateId();
diff --git a/chromium/ui/android/features.gni b/chromium/ui/android/features.gni
new file mode 100644
index 00000000000..a8dfa5004ad
--- /dev/null
+++ b/chromium/ui/android/features.gni
@@ -0,0 +1,7 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+ enable_android_night_mode = false
+}
diff --git a/chromium/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java b/chromium/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java
new file mode 100644
index 00000000000..241bc14ab94
--- /dev/null
+++ b/chromium/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java
@@ -0,0 +1,364 @@
+// 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.modaldialog;
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Feature;
+import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests to validate actions within {@link ModalDialogManager}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ModalDialogManagerTest {
+ private static final int MAX_DIALOGS = 4;
+
+ @Mock
+ private ModalDialogManager.Presenter mAppModalPresenter;
+ @Mock
+ private ModalDialogManager.Presenter mTabModalPresenter;
+
+ private ModalDialogManager mModalDialogManager;
+ private List<PropertyModel> mDialogModels = new ArrayList<>();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mModalDialogManager = new ModalDialogManager(mAppModalPresenter, ModalDialogType.APP);
+ mModalDialogManager.registerPresenter(mTabModalPresenter, ModalDialogType.TAB);
+
+ for (int i = 0; i < MAX_DIALOGS; ++i) {
+ ModalDialogProperties.Controller controller = new ModalDialogProperties.Controller() {
+ @Override
+ public void onClick(PropertyModel model, int buttonType) {}
+
+ @Override
+ public void onDismiss(PropertyModel model, int dismissalCause) {}
+ };
+
+ mDialogModels.add(new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
+ .with(ModalDialogProperties.CONTROLLER, spy(controller))
+ .build());
+ }
+ }
+
+ /** Tests showing a dialog when no dialog is currently showing. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testShowDialog_NoDialogIsShowing() {
+ // Show an app modal dialog and verify that it is showing.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.APP);
+ assertTrue(mModalDialogManager.isShowing());
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB));
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+ }
+
+ /**
+ * Tests showing a dialog when another dialog of same or higher priority is currently showing.
+ */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testShowDialog_DialogOfSameOrHigherPriorityIsShowing() {
+ // Show an app modal dialog and verify that it is showing.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+
+ // Show another app modal dialog and verify that it is queued.
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB));
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+ verify(mAppModalPresenter, times(0)).addDialogView(mDialogModels.get(1));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+
+ // Show a tab modal dialog and verify that it is queued.
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.TAB);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+ verify(mAppModalPresenter, times(0)).addDialogView(mDialogModels.get(1));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+ }
+
+ /** Tests showing a dialog when another dialog of lower priority is currently showing. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testShowDialog_DialogOfLowerPriorityIsShowing() {
+ // Show a tab modal dialog and verify that it is showing.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.TAB);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ verify(mAppModalPresenter, times(0)).addDialogView(any());
+ verify(mTabModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+
+ // Show an app modal dialog, and verify that the app modal dialog is shown, and the tab
+ // modal dialog is queued.
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(1), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ verify(mAppModalPresenter, times(0)).addDialogView(mDialogModels.get(0));
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(1));
+ verify(mTabModalPresenter, times(1)).addDialogView(any());
+ }
+
+ /**
+ * Tests whether the next dialog in the pending queue is correctly shown after the current
+ * dialog is dismissed.
+ */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testShowDialog_ShowNextDialogAfterDismiss() {
+ // Show an app modal dialog and verify that it is showing.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+
+ // Show a second and a third app modal dialog and verify that they are queued.
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.APP);
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(2, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB));
+ verify(mAppModalPresenter, times(1)).addDialogView(any());
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+
+ // Dismiss the first dialog and verify that the second dialog is shown.
+ mModalDialogManager.dismissDialog(mDialogModels.get(0), ModalDialogType.APP);
+ assertOnDismissCalled(mDialogModels.get(0), 1);
+ assertEquals(mDialogModels.get(1), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB));
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(1));
+ verify(mAppModalPresenter, times(0)).addDialogView(mDialogModels.get(2));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+ }
+
+ /** Tests showing a dialog as the next available dialog in the pending queue. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testShowDialog_ShowAsNext() {
+ // Show an app modal dialog and verify that it is showing.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+
+ // Show a second app modal dialog and verify that it is queued.
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB));
+ verify(mAppModalPresenter, times(1)).addDialogView(any());
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+
+ // Show a third app modal dialog as next and verify that it is queued.
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.APP, true);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(2, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB));
+ verify(mAppModalPresenter, times(1)).addDialogView(any());
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+
+ // Dismiss the first dialog and verify that the third dialog is shown.
+ mModalDialogManager.dismissDialog(mDialogModels.get(0), ModalDialogType.APP);
+ assertOnDismissCalled(mDialogModels.get(0), 1);
+ assertEquals(mDialogModels.get(2), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB));
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+ verify(mAppModalPresenter, times(0)).addDialogView(mDialogModels.get(1));
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(2));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+ }
+
+ /** Tests dismissing the current dialog. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testDismissDialog_CurrentDialog() {
+ // Show an app modal dialog and verify that it is showing.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(0));
+
+ // Show a tab modal dialog then a second app modal dialog and verify that they are queued.
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.TAB);
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+
+ // Dismiss the current dialog and the second app modal dialog should be showing next.
+ mModalDialogManager.dismissDialog(mDialogModels.get(0), DialogDismissalCause.UNKNOWN);
+ assertOnDismissCalled(mDialogModels.get(0), 1);
+ assertEquals(mDialogModels.get(2), mModalDialogManager.getCurrentDialogForTest());
+ verify(mAppModalPresenter, times(1)).removeDialogView(mDialogModels.get(0));
+
+ assertTrue(mModalDialogManager.isShowing());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ verify(mAppModalPresenter, times(1)).addDialogView(mDialogModels.get(2));
+ verify(mTabModalPresenter, times(0)).addDialogView(any());
+
+ // Dismiss the first dialog again and verify nothing is changed.
+ mModalDialogManager.dismissDialog(mDialogModels.get(0), DialogDismissalCause.UNKNOWN);
+ assertOnDismissCalled(mDialogModels.get(0), 1);
+ assertEquals(mDialogModels.get(2), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ Mockito.verifyNoMoreInteractions(mAppModalPresenter, mTabModalPresenter);
+ }
+
+ /** Tests dismissing a dialog in the pending queue. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testDismissDialog_DialogInQueue() {
+ // Show three dialogs.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.APP);
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.APP);
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.TAB);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+
+ // Dismiss the second dialog.
+ mModalDialogManager.dismissDialog(mDialogModels.get(1), DialogDismissalCause.UNKNOWN);
+ assertOnDismissCalled(mDialogModels.get(1), 1);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(1, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+
+ // Dismiss the third dialog.
+ mModalDialogManager.dismissDialog(mDialogModels.get(2), DialogDismissalCause.UNKNOWN);
+ assertOnDismissCalled(mDialogModels.get(2), 1);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ }
+
+ /** Tests dismissing all dialogs. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testDismissAllDialogs() {
+ // Show three dialogs.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.APP);
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.APP);
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.TAB);
+
+ // Dismiss all dialog.
+ mModalDialogManager.dismissAllDialogs(DialogDismissalCause.UNKNOWN);
+ assertOnDismissCalled(mDialogModels.get(0), 1);
+ assertOnDismissCalled(mDialogModels.get(1), 1);
+ assertOnDismissCalled(mDialogModels.get(2), 1);
+ assertFalse(mModalDialogManager.isShowing());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ }
+
+ /** Tests dismissing dialogs of a certain type. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testDismissDialogsOfType() {
+ // Show three dialogs.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.APP);
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.APP);
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.TAB);
+
+ // Dismiss all app modal dialogs.
+ mModalDialogManager.dismissDialogsOfType(ModalDialogType.APP, DialogDismissalCause.UNKNOWN);
+ assertOnDismissCalled(mDialogModels.get(0), 1);
+ assertOnDismissCalled(mDialogModels.get(1), 1);
+ assertEquals(mDialogModels.get(2), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ }
+
+ /** Tests suspending dialogs of a certain type. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testSuspendType() {
+ // Show two tab modal dialogs.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.TAB);
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.TAB);
+
+ // Suspend all tab modal dialogs. onDismiss() should not be called.
+ mModalDialogManager.suspendType(ModalDialogType.TAB);
+ assertOnDismissCalled(mDialogModels.get(0), 0);
+ assertOnDismissCalled(mDialogModels.get(1), 0);
+ assertFalse(mModalDialogManager.isShowing());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP));
+ assertEquals(2, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+
+ // Show a third tab modal dialog, and verify that it is queued.
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.TAB);
+ assertFalse(mModalDialogManager.isShowing());
+ assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP));
+ assertEquals(3, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+
+ // Show an app modal dialog, and verify that it is shown.
+ mModalDialogManager.showDialog(mDialogModels.get(3), ModalDialogType.APP);
+ assertEquals(mDialogModels.get(3), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(0, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP).size());
+ assertEquals(3, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ }
+
+ /** Tests resuming dialogs of a certain type. */
+ @Test
+ @Feature({"ModalDialog"})
+ public void testResumeType() {
+ // Show three tab modal dialogs.
+ mModalDialogManager.showDialog(mDialogModels.get(0), ModalDialogType.TAB);
+ mModalDialogManager.showDialog(mDialogModels.get(1), ModalDialogType.TAB);
+ mModalDialogManager.showDialog(mDialogModels.get(2), ModalDialogType.TAB);
+
+ // Suspend all tab modal dialogs.
+ mModalDialogManager.suspendType(ModalDialogType.TAB);
+ assertFalse(mModalDialogManager.isShowing());
+ assertEquals(3, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+
+ // Resume tab modal dialogs.
+ mModalDialogManager.resumeType(ModalDialogType.TAB);
+ assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
+ assertEquals(2, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
+ }
+
+ private static void assertOnDismissCalled(PropertyModel model, int numberOfInvocations) {
+ verify(model.get(ModalDialogProperties.CONTROLLER), times(numberOfInvocations))
+ .onDismiss(eq(model), anyInt());
+ }
+}
diff --git a/chromium/ui/android/junit/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcpTest.java b/chromium/ui/android/junit/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcpTest.java
new file mode 100644
index 00000000000..b87dcc2f204
--- /dev/null
+++ b/chromium/ui/android/junit/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcpTest.java
@@ -0,0 +1,169 @@
+// 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.modelutil;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.support.annotation.Nullable;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLooper;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
+import org.chromium.ui.test.util.modelutil.FakeViewProvider;
+
+/**
+ * Unit tests for LazyConstructionPropertyMcp.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class LazyConstructionPropertyMcpTest {
+ private static final WritableBooleanPropertyKey VISIBILITY = new WritableBooleanPropertyKey();
+ private static final WritableObjectPropertyKey<String> STRING_PROPERTY =
+ new WritableObjectPropertyKey<>();
+ private static final WritableIntPropertyKey INT_PROPERTY = new WritableIntPropertyKey();
+ private static final PropertyKey[] ALL_PROPERTIES =
+ new PropertyKey[] {VISIBILITY, STRING_PROPERTY, INT_PROPERTY};
+ private PropertyModel mModel;
+ private FakeViewProvider<View> mViewProvider;
+ private @Nullable PropertyObservable.PropertyObserver<PropertyKey> mModelObserver;
+
+ @Mock
+ private View mView;
+ @Mock
+ private ViewBinder<PropertyModel, View, PropertyKey> mViewBinder;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mModel = new PropertyModel(ALL_PROPERTIES);
+ mModel.set(VISIBILITY, false);
+ mViewProvider = new FakeViewProvider<>();
+ mModel.addObserver((source, propertyKey) -> {
+ // Forward model changes to the model observer if it exists. It's important for the test
+ // that the observer is notified before the LazyConstructionPropertyMcp.
+ if (mModelObserver != null) mModelObserver.onPropertyChanged(source, propertyKey);
+ });
+ }
+
+ @Test
+ public void testInitialConstruction() {
+ LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
+ assertFalse(mViewProvider.inflationHasStarted());
+
+ mModel.set(VISIBILITY, true);
+
+ assertTrue(mViewProvider.inflationHasStarted());
+ mViewProvider.finishInflation(mView);
+ ShadowLooper.idleMainLooper();
+
+ verifyBind(VISIBILITY);
+ }
+
+ @Test
+ public void testUpdatesBeforeInflation() {
+ LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
+ mModel.set(STRING_PROPERTY, "foo");
+ mModel.set(VISIBILITY, true);
+ assertTrue(mViewProvider.inflationHasStarted());
+ mViewProvider.finishInflation(mView);
+ ShadowLooper.idleMainLooper();
+ verifyBind(STRING_PROPERTY, VISIBILITY);
+ }
+
+ @Test
+ public void testUpdatesWhileVisible() {
+ LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
+
+ // Show the view and pump the looper to do the initial bind.
+ mModel.set(VISIBILITY, true);
+ assertTrue(mViewProvider.inflationHasStarted());
+ mViewProvider.finishInflation(mView);
+ ShadowLooper.idleMainLooper();
+ verifyBind(VISIBILITY);
+ Mockito.<ViewBinder>reset(mViewBinder);
+
+ mModel.set(INT_PROPERTY, 42);
+ verifyBind(INT_PROPERTY);
+
+ mModel.set(VISIBILITY, false);
+ verifyBind(VISIBILITY);
+ }
+
+ @Test
+ public void testUpdatesWhileHidden() {
+ LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
+
+ // Show the view and pump the looper to do the initial bind, then hide the view again.
+ mModel.set(VISIBILITY, true);
+ assertTrue(mViewProvider.inflationHasStarted());
+ mViewProvider.finishInflation(mView);
+ ShadowLooper.idleMainLooper();
+ verifyBind(VISIBILITY);
+
+ mModel.set(VISIBILITY, false);
+ verify(mViewBinder, times(2)).bind(eq(mModel), eq(mView), eq(VISIBILITY));
+ Mockito.<ViewBinder>reset(mViewBinder);
+
+ // While the view is hidden, the binder should not be invoked.
+ mModel.set(STRING_PROPERTY, "foo");
+ mModel.set(STRING_PROPERTY, "bar");
+ verify(mViewBinder, never())
+ .bind(any(PropertyModel.class), any(View.class), any(PropertyKey.class));
+
+ // When the view is shown, all pending updates should be dispatched, coalescing updates to
+ // the same property.
+ mModel.set(VISIBILITY, true);
+ verifyBind(VISIBILITY, STRING_PROPERTY);
+ }
+
+ @Test
+ public void testReentrantUpdates() {
+ mModel.set(INT_PROPERTY, 0);
+ LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
+
+ // Increase INT_PROPERTY any time visibility changes.
+ mModelObserver = (source, propertyKey) -> {
+ if (propertyKey != VISIBILITY) return;
+ mModel.set(INT_PROPERTY, mModel.get(INT_PROPERTY) + 1);
+ };
+
+ mModel.set(VISIBILITY, true);
+ mViewProvider.finishInflation(mView);
+ ShadowLooper.idleMainLooper();
+ verifyBind(VISIBILITY, INT_PROPERTY);
+ assertThat(mModel.get(INT_PROPERTY), is(1));
+ Mockito.<ViewBinder>reset(mViewBinder);
+
+ mModel.set(VISIBILITY, false);
+ verifyBind(INT_PROPERTY, VISIBILITY);
+ assertThat(mModel.get(INT_PROPERTY), is(2));
+ }
+
+ private void verifyBind(PropertyKey... properties) {
+ for (PropertyKey key : properties) {
+ verify(mViewBinder).bind(mModel, mView, key);
+ }
+ }
+}
diff --git a/chromium/ui/android/junit/src/org/chromium/ui/modelutil/PropertyModelTest.java b/chromium/ui/android/junit/src/org/chromium/ui/modelutil/PropertyModelTest.java
new file mode 100644
index 00000000000..4f68cf49dcd
--- /dev/null
+++ b/chromium/ui/android/junit/src/org/chromium/ui/modelutil/PropertyModelTest.java
@@ -0,0 +1,219 @@
+// 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.modelutil;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.equalTo;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableFloatPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
+import org.chromium.ui.modelutil.PropertyObservable.PropertyObserver;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Tests to ensure/validate the interactions with the PropertyModel.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class PropertyModelTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ public static WritableBooleanPropertyKey BOOLEAN_PROPERTY_A = new WritableBooleanPropertyKey();
+ public static WritableBooleanPropertyKey BOOLEAN_PROPERTY_B = new WritableBooleanPropertyKey();
+ public static WritableBooleanPropertyKey BOOLEAN_PROPERTY_C = new WritableBooleanPropertyKey();
+
+ public static WritableFloatPropertyKey FLOAT_PROPERTY_A = new WritableFloatPropertyKey();
+ public static WritableFloatPropertyKey FLOAT_PROPERTY_B = new WritableFloatPropertyKey();
+ public static WritableFloatPropertyKey FLOAT_PROPERTY_C = new WritableFloatPropertyKey();
+
+ public static WritableIntPropertyKey INT_PROPERTY_A = new WritableIntPropertyKey();
+ public static WritableIntPropertyKey INT_PROPERTY_B = new WritableIntPropertyKey();
+ public static WritableIntPropertyKey INT_PROPERTY_C = new WritableIntPropertyKey();
+
+ public static WritableObjectPropertyKey<Object> OBJECT_PROPERTY_A =
+ new WritableObjectPropertyKey<>();
+ public static WritableObjectPropertyKey<String> OBJECT_PROPERTY_B =
+ new WritableObjectPropertyKey<>();
+ public static WritableObjectPropertyKey<List<Integer>> OBJECT_PROPERTY_C =
+ new WritableObjectPropertyKey<>();
+
+ @Test
+ public void getAllSetProperties() {
+ PropertyModel model = new PropertyModel(
+ BOOLEAN_PROPERTY_A, FLOAT_PROPERTY_A, INT_PROPERTY_A, OBJECT_PROPERTY_A);
+ model.set(BOOLEAN_PROPERTY_A, true);
+ model.set(INT_PROPERTY_A, 42);
+ Collection<PropertyKey> setProperties = model.getAllSetProperties();
+ assertThat(setProperties, containsInAnyOrder(BOOLEAN_PROPERTY_A, INT_PROPERTY_A));
+ assertThat(setProperties.size(), equalTo(2));
+ }
+
+ @Test
+ public void booleanUpdates() {
+ PropertyModel model = new PropertyModel(BOOLEAN_PROPERTY_A, BOOLEAN_PROPERTY_B);
+
+ verifyBooleanUpdate(model, BOOLEAN_PROPERTY_A, false);
+ verifyBooleanUpdate(model, BOOLEAN_PROPERTY_A, true);
+ verifyBooleanUpdate(model, BOOLEAN_PROPERTY_B, true);
+ verifyBooleanUpdate(model, BOOLEAN_PROPERTY_B, false);
+ }
+
+ private void verifyBooleanUpdate(
+ PropertyModel model, WritableBooleanPropertyKey key, boolean value) {
+ @SuppressWarnings("unchecked")
+ PropertyObserver<PropertyKey> observer = Mockito.mock(PropertyObserver.class);
+ model.addObserver(observer);
+ Mockito.<PropertyObserver>reset(observer);
+
+ model.set(key, value);
+ verify(observer).onPropertyChanged(model, key);
+ assertThat(model.get(key), equalTo(value));
+
+ model.removeObserver(observer);
+ }
+
+ @Test
+ public void floatUpdates() {
+ PropertyModel model =
+ new PropertyModel(FLOAT_PROPERTY_A, FLOAT_PROPERTY_B, FLOAT_PROPERTY_C);
+
+ verifyFloatUpdate(model, FLOAT_PROPERTY_A, 0f);
+ verifyFloatUpdate(model, FLOAT_PROPERTY_B, 1f);
+ verifyFloatUpdate(model, FLOAT_PROPERTY_C, -1f);
+
+ verifyFloatUpdate(model, FLOAT_PROPERTY_A, Float.NaN);
+ verifyFloatUpdate(model, FLOAT_PROPERTY_A, Float.NEGATIVE_INFINITY);
+ verifyFloatUpdate(model, FLOAT_PROPERTY_A, Float.POSITIVE_INFINITY);
+ verifyFloatUpdate(model, FLOAT_PROPERTY_A, Float.MIN_VALUE);
+ verifyFloatUpdate(model, FLOAT_PROPERTY_A, Float.MAX_VALUE);
+ }
+
+ private void verifyFloatUpdate(PropertyModel model, WritableFloatPropertyKey key, float value) {
+ @SuppressWarnings("unchecked")
+ PropertyObserver<PropertyKey> observer = Mockito.mock(PropertyObserver.class);
+ model.addObserver(observer);
+ Mockito.<PropertyObserver>reset(observer);
+
+ model.set(key, value);
+ verify(observer).onPropertyChanged(model, key);
+ assertThat(model.get(key), equalTo(value));
+
+ model.removeObserver(observer);
+ }
+
+ @Test
+ public void intUpdates() {
+ PropertyModel model = new PropertyModel(INT_PROPERTY_A, INT_PROPERTY_B, INT_PROPERTY_C);
+
+ verifyIntUpdate(model, INT_PROPERTY_A, 0);
+ verifyIntUpdate(model, INT_PROPERTY_B, -1);
+ verifyIntUpdate(model, INT_PROPERTY_C, 1);
+
+ verifyIntUpdate(model, INT_PROPERTY_A, Integer.MAX_VALUE);
+ verifyIntUpdate(model, INT_PROPERTY_A, Integer.MIN_VALUE);
+ }
+
+ private void verifyIntUpdate(PropertyModel model, WritableIntPropertyKey key, int value) {
+ @SuppressWarnings("unchecked")
+ PropertyObserver<PropertyKey> observer = Mockito.mock(PropertyObserver.class);
+ model.addObserver(observer);
+ Mockito.<PropertyObserver>reset(observer);
+
+ model.set(key, value);
+ verify(observer).onPropertyChanged(model, key);
+ assertThat(model.get(key), equalTo(value));
+
+ model.removeObserver(observer);
+ }
+
+ @Test
+ public void objectUpdates() {
+ PropertyModel model =
+ new PropertyModel(OBJECT_PROPERTY_A, OBJECT_PROPERTY_B, OBJECT_PROPERTY_C);
+
+ verifyObjectUpdate(model, OBJECT_PROPERTY_A, new Object());
+ verifyObjectUpdate(model, OBJECT_PROPERTY_A, null);
+
+ verifyObjectUpdate(model, OBJECT_PROPERTY_B, "Test");
+ verifyObjectUpdate(model, OBJECT_PROPERTY_B, "Test1");
+ verifyObjectUpdate(model, OBJECT_PROPERTY_B, null);
+ verifyObjectUpdate(model, OBJECT_PROPERTY_B, "Test");
+
+ List<Integer> list = new ArrayList<>();
+ verifyObjectUpdate(model, OBJECT_PROPERTY_C, list);
+ list = new ArrayList<>(list);
+ list.add(1);
+ verifyObjectUpdate(model, OBJECT_PROPERTY_C, list);
+ list = new ArrayList<>(list);
+ list.add(2);
+ verifyObjectUpdate(model, OBJECT_PROPERTY_C, list);
+ }
+
+ private <T> void verifyObjectUpdate(
+ PropertyModel model, WritableObjectPropertyKey<T> key, T value) {
+ @SuppressWarnings("unchecked")
+ PropertyObserver<PropertyKey> observer = Mockito.mock(PropertyObserver.class);
+ model.addObserver(observer);
+ Mockito.<PropertyObserver>reset(observer);
+
+ model.set(key, value);
+ verify(observer).onPropertyChanged(model, key);
+ assertThat(model.get(key), equalTo(value));
+
+ model.removeObserver(observer);
+ }
+
+ @Test
+ public void duplicateSetChangeSuppression() {
+ PropertyModel model = new PropertyModel(
+ BOOLEAN_PROPERTY_A, FLOAT_PROPERTY_A, INT_PROPERTY_A, OBJECT_PROPERTY_A);
+ model.set(BOOLEAN_PROPERTY_A, true);
+ model.set(FLOAT_PROPERTY_A, 1f);
+ model.set(INT_PROPERTY_A, -1);
+
+ Object obj = new Object();
+ model.set(OBJECT_PROPERTY_A, obj);
+
+ @SuppressWarnings("unchecked")
+ PropertyObserver<PropertyKey> observer = Mockito.mock(PropertyObserver.class);
+ model.addObserver(observer);
+ Mockito.<PropertyObserver>reset(observer);
+
+ model.set(BOOLEAN_PROPERTY_A, true);
+ model.set(FLOAT_PROPERTY_A, 1f);
+ model.set(INT_PROPERTY_A, -1);
+ model.set(OBJECT_PROPERTY_A, obj);
+
+ Mockito.verifyZeroInteractions(observer);
+ }
+
+ @Test
+ public void ensureValidKey() {
+ PropertyModel model = new PropertyModel(BOOLEAN_PROPERTY_A, BOOLEAN_PROPERTY_B);
+ thrown.expect(IllegalArgumentException.class);
+ model.set(BOOLEAN_PROPERTY_C, true);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void preventsDuplicateKeys() {
+ new PropertyModel(BOOLEAN_PROPERTY_A, BOOLEAN_PROPERTY_A);
+ }
+}
diff --git a/chromium/ui/android/junit/src/org/chromium/ui/modelutil/SimpleListObservableTest.java b/chromium/ui/android/junit/src/org/chromium/ui/modelutil/SimpleListObservableTest.java
new file mode 100644
index 00000000000..06dd00980c5
--- /dev/null
+++ b/chromium/ui/android/junit/src/org/chromium/ui/modelutil/SimpleListObservableTest.java
@@ -0,0 +1,107 @@
+// 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.modelutil;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.ui.modelutil.ListObservable.ListObserver;
+
+/**
+ * Basic test ensuring the {@link ListModel} notifies listeners properly.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class SimpleListObservableTest {
+ @Mock
+ private ListObserver<Void> mObserver;
+
+ private ListModel<Integer> mIntegerList = new ListModel<>();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mIntegerList.addObserver(mObserver);
+ }
+
+ @After
+ public void tearDown() {
+ mIntegerList.removeObserver(mObserver);
+ }
+
+ @Test
+ public void testNotifiesSuccessfulInsertions() {
+ // Replacing an empty list with a non-empty one is always an insertion.
+ assertThat(mIntegerList.size(), is(0));
+ mIntegerList.set(new Integer[] {333, 88888888, 22});
+ verify(mObserver).onItemRangeInserted(mIntegerList, 0, 3);
+ assertThat(mIntegerList.size(), is(3));
+ assertThat(mIntegerList.get(1), is(88888888));
+
+ // Adding Items is always an insertion.
+ mIntegerList.add(55555);
+ verify(mObserver).onItemRangeInserted(mIntegerList, 3, 1);
+ assertThat(mIntegerList.size(), is(4));
+ assertThat(mIntegerList.get(3), is(55555));
+ }
+
+ @Test
+ public void testModelNotifiesSuccessfulRemoval() {
+ Integer eightEights = 88888888;
+ mIntegerList.set(new Integer[] {333, eightEights, 22});
+ assertThat(mIntegerList.size(), is(3));
+
+ // Removing any item by instance is always a removal.
+ mIntegerList.remove(eightEights);
+ verify(mObserver).onItemRangeRemoved(mIntegerList, 1, 1);
+
+ // Setting an empty list is a removal of all items.
+ mIntegerList.set(new Integer[] {});
+ verify(mObserver).onItemRangeRemoved(mIntegerList, 0, 2);
+ }
+
+ @Test
+ public void testModelNotifiesReplacedDataAndRemoval() {
+ // The initial setting is an insertion.
+ mIntegerList.set(new Integer[] {333, 88888888, 22});
+ verify(mObserver).onItemRangeInserted(mIntegerList, 0, 3);
+
+ // Setting a smaller number of items is a removal and a change.
+ mIntegerList.set(new Integer[] {4444, 22});
+ verify(mObserver).onItemRangeChanged(mIntegerList, 0, 2, null);
+ verify(mObserver).onItemRangeRemoved(mIntegerList, 2, 1);
+ }
+
+ @Test
+ public void testModelNotifiesReplacedDataAndInsertion() {
+ // The initial setting is an insertion.
+ mIntegerList.set(new Integer[] {1234, 56});
+ verify(mObserver).onItemRangeInserted(mIntegerList, 0, 2);
+
+ // Setting a larger number of items is an insertion and a change.
+ mIntegerList.set(new Integer[] {4444, 22, 1, 666666});
+ verify(mObserver).onItemRangeChanged(mIntegerList, 0, 2, null);
+ verify(mObserver).onItemRangeInserted(mIntegerList, 2, 2);
+
+ // Setting empty data is a removal.
+ mIntegerList.set(new Integer[] {});
+ verify(mObserver).onItemRangeRemoved(mIntegerList, 0, 4);
+
+ // Replacing an empty list with another empty list is a no-op.
+ mIntegerList.set(new Integer[] {});
+ verifyNoMoreInteractions(mObserver);
+ }
+} \ No newline at end of file
diff --git a/chromium/ui/android/junit/src/org/chromium/ui/text/SpanApplierTest.java b/chromium/ui/android/junit/src/org/chromium/ui/text/SpanApplierTest.java
index 7b8fc7ace75..61464cae285 100644
--- a/chromium/ui/android/junit/src/org/chromium/ui/text/SpanApplierTest.java
+++ b/chromium/ui/android/junit/src/org/chromium/ui/text/SpanApplierTest.java
@@ -30,7 +30,7 @@ public class SpanApplierTest {
SpanInfo span = new SpanInfo("<span>", "</span>", new QuoteSpan());
SpannableString expectedOutput = new SpannableString(output);
- expectedOutput.setSpan(span.mSpan, 12, 17, 0);
+ expectedOutput.setSpan(span.mSpans[0], 12, 17, 0);
SpannableString actualOutput = SpanApplier.applySpans(input, span);
assertSpannableStringEquality(expectedOutput, actualOutput);
@@ -47,15 +47,29 @@ public class SpanApplierTest {
SpanInfo elitSpan = new SpanInfo("<elit>", "<endElit>", new ScaleXSpan(1));
SpannableString expectedOutput = new SpannableString(output);
- expectedOutput.setSpan(linkSpan.mSpan, 6, 11, 0);
- expectedOutput.setSpan(consSpan.mSpan, 28, 50, 0);
- expectedOutput.setSpan(elitSpan.mSpan, 51, 62, 0);
+ expectedOutput.setSpan(linkSpan.mSpans[0], 6, 11, 0);
+ expectedOutput.setSpan(consSpan.mSpans[0], 28, 50, 0);
+ expectedOutput.setSpan(elitSpan.mSpans[0], 51, 62, 0);
SpannableString actualOutput = SpanApplier.applySpans(input, elitSpan, consSpan, linkSpan);
assertSpannableStringEquality(expectedOutput, actualOutput);
}
@Test
+ public void testVarargSpanInfoConstructor() {
+ String input = "Lorem ipsum <span>dolor</span> sit amet.";
+ String output = "Lorem ipsum dolor sit amet.";
+ SpanInfo multiSpan = new SpanInfo("<span>", "</span>", new QuoteSpan(), new BulletSpan());
+
+ SpannableString expectedOutput = new SpannableString(output);
+ expectedOutput.setSpan(multiSpan.mSpans[0], 12, 17, 0);
+ expectedOutput.setSpan(multiSpan.mSpans[1], 12, 17, 0);
+ SpannableString actualOutput = SpanApplier.applySpans(input, multiSpan);
+
+ assertSpannableStringEquality(expectedOutput, actualOutput);
+ }
+
+ @Test
public void testEndTagMissingInInput() {
String input = "Lorem ipsum <span>dolor</> sit amet.";
SpanInfo span = new SpanInfo("<span>", "</span>", new QuoteSpan());
@@ -113,11 +127,11 @@ public class SpanApplierTest {
public void testNullSpan() {
String input = "Lorem <link>ipsum</link> dolor <span>sit</span> amet.";
SpanInfo linkSpan = new SpanInfo("<link>", "</link>", new QuoteSpan());
- SpanInfo nullSpan = new SpanInfo("<span>", "</span>", null);
+ SpanInfo nullSpan = new SpanInfo("<span>", "</span>", (Object) null);
String output = "Lorem ipsum dolor sit amet.";
SpannableString expectedOutput = new SpannableString(output);
- expectedOutput.setSpan(linkSpan.mSpan, 6, 11, 0);
+ expectedOutput.setSpan(linkSpan.mSpans[0], 6, 11, 0);
SpannableString actualOutput = SpanApplier.applySpans(input, linkSpan, nullSpan);
assertSpannableStringEquality(expectedOutput, actualOutput);
diff --git a/chromium/ui/android/overscroll_refresh.cc b/chromium/ui/android/overscroll_refresh.cc
index 60b54aa3dc1..2b6077dce24 100644
--- a/chromium/ui/android/overscroll_refresh.cc
+++ b/chromium/ui/android/overscroll_refresh.cc
@@ -18,6 +18,7 @@ const float kMinFlingVelocityForActivation = -500.f;
OverscrollRefresh::OverscrollRefresh(OverscrollRefreshHandler* handler)
: scrolled_to_top_(true),
+ top_at_scroll_start_(true),
overflow_y_hidden_(false),
scroll_consumption_state_(DISABLED),
handler_(handler) {
@@ -35,13 +36,15 @@ OverscrollRefresh::~OverscrollRefresh() {
void OverscrollRefresh::Reset() {
scroll_consumption_state_ = DISABLED;
+ cumulative_scroll_.set_x(0);
+ cumulative_scroll_.set_y(0);
handler_->PullReset();
}
void OverscrollRefresh::OnScrollBegin() {
+ top_at_scroll_start_ = scrolled_to_top_;
ReleaseWithoutActivation();
- if (scrolled_to_top_ && !overflow_y_hidden_)
- scroll_consumption_state_ = AWAITING_SCROLL_UPDATE_ACK;
+ scroll_consumption_state_ = AWAITING_SCROLL_UPDATE_ACK;
}
void OverscrollRefresh::OnScrollEnd(const gfx::Vector2dF& scroll_velocity) {
@@ -53,7 +56,10 @@ void OverscrollRefresh::OnOverscrolled() {
if (scroll_consumption_state_ != AWAITING_SCROLL_UPDATE_ACK)
return;
- scroll_consumption_state_ = handler_->PullStart() ? ENABLED : DISABLED;
+ scroll_consumption_state_ =
+ handler_->PullStart(cumulative_scroll_.x(), cumulative_scroll_.y())
+ ? ENABLED
+ : DISABLED;
}
bool OverscrollRefresh::WillHandleScrollUpdate(
@@ -63,13 +69,21 @@ bool OverscrollRefresh::WillHandleScrollUpdate(
return false;
case AWAITING_SCROLL_UPDATE_ACK:
- // If the initial scroll motion is downward, never allow activation.
- if (scroll_delta.y() <= 0)
- scroll_consumption_state_ = DISABLED;
+ // Check applies for the pull-to-refresh condition only.
+ if (std::abs(scroll_delta.y()) > std::abs(scroll_delta.x())) {
+ // If the initial scroll motion is downward, or we're in other cases
+ // where activation shouldn't have happened, stop here.
+ if (scroll_delta.y() <= 0 || !top_at_scroll_start_ ||
+ overflow_y_hidden_) {
+ scroll_consumption_state_ = DISABLED;
+ return false;
+ }
+ }
+ cumulative_scroll_.Add(scroll_delta);
return false;
case ENABLED:
- handler_->PullUpdate(scroll_delta.y());
+ handler_->PullUpdate(scroll_delta.x(), scroll_delta.y());
return true;
}
@@ -101,6 +115,8 @@ void OverscrollRefresh::Release(bool allow_refresh) {
if (scroll_consumption_state_ == ENABLED)
handler_->PullRelease(allow_refresh);
scroll_consumption_state_ = DISABLED;
+ cumulative_scroll_.set_x(0);
+ cumulative_scroll_.set_y(0);
}
} // namespace ui
diff --git a/chromium/ui/android/overscroll_refresh.h b/chromium/ui/android/overscroll_refresh.h
index b9067f17364..25bc168f59b 100644
--- a/chromium/ui/android/overscroll_refresh.h
+++ b/chromium/ui/android/overscroll_refresh.h
@@ -77,6 +77,9 @@ class UI_ANDROID_EXPORT OverscrollRefresh {
void Release(bool allow_refresh);
bool scrolled_to_top_;
+ // True if the content y offset was zero before scroll began. Overscroll
+ // should not be triggered for the scroll that started from non-zero offset.
+ bool top_at_scroll_start_;
bool overflow_y_hidden_;
enum ScrollConsumptionState {
@@ -85,6 +88,7 @@ class UI_ANDROID_EXPORT OverscrollRefresh {
ENABLED,
} scroll_consumption_state_;
+ gfx::Vector2dF cumulative_scroll_;
OverscrollRefreshHandler* const handler_;
DISALLOW_COPY_AND_ASSIGN(OverscrollRefresh);
diff --git a/chromium/ui/android/overscroll_refresh_handler.cc b/chromium/ui/android/overscroll_refresh_handler.cc
index 49b2f715423..63e98735b86 100644
--- a/chromium/ui/android/overscroll_refresh_handler.cc
+++ b/chromium/ui/android/overscroll_refresh_handler.cc
@@ -19,14 +19,14 @@ OverscrollRefreshHandler::OverscrollRefreshHandler(
OverscrollRefreshHandler::~OverscrollRefreshHandler() {}
-bool OverscrollRefreshHandler::PullStart() {
- return Java_OverscrollRefreshHandler_start(AttachCurrentThread(),
- j_overscroll_refresh_handler_);
+bool OverscrollRefreshHandler::PullStart(float x_delta, float y_delta) {
+ return Java_OverscrollRefreshHandler_start(
+ AttachCurrentThread(), j_overscroll_refresh_handler_, x_delta, y_delta);
}
-void OverscrollRefreshHandler::PullUpdate(float delta) {
- Java_OverscrollRefreshHandler_pull(AttachCurrentThread(),
- j_overscroll_refresh_handler_, delta);
+void OverscrollRefreshHandler::PullUpdate(float x_delta, float y_delta) {
+ Java_OverscrollRefreshHandler_pull(
+ AttachCurrentThread(), j_overscroll_refresh_handler_, x_delta, y_delta);
}
void OverscrollRefreshHandler::PullRelease(bool allow_refresh) {
diff --git a/chromium/ui/android/overscroll_refresh_handler.h b/chromium/ui/android/overscroll_refresh_handler.h
index 60184bf9046..7b4b7fa386e 100644
--- a/chromium/ui/android/overscroll_refresh_handler.h
+++ b/chromium/ui/android/overscroll_refresh_handler.h
@@ -23,10 +23,10 @@ class UI_ANDROID_EXPORT OverscrollRefreshHandler {
// Signals the start of an overscrolling pull. Returns whether the handler
// will consume the overscroll gesture, in which case it will receive the
// remaining pull updates.
- virtual bool PullStart();
+ virtual bool PullStart(float x_delta, float y_delta);
- // Signals a pull update, where |delta| is in device pixels.
- virtual void PullUpdate(float delta);
+ // Signals a pull update, where |x_delta| and |y_delta| are in device pixels.
+ virtual void PullUpdate(float x_delta, float y_delta);
// Signals the release of the pull, and whether the release is allowed to
// trigger the refresh action.
diff --git a/chromium/ui/android/overscroll_refresh_unittest.cc b/chromium/ui/android/overscroll_refresh_unittest.cc
index f31b85f4504..bcd1e6575bd 100644
--- a/chromium/ui/android/overscroll_refresh_unittest.cc
+++ b/chromium/ui/android/overscroll_refresh_unittest.cc
@@ -16,12 +16,12 @@ class OverscrollRefreshTest : public OverscrollRefreshHandler,
OverscrollRefreshTest() : OverscrollRefreshHandler(nullptr) {}
// OverscrollRefreshHandler implementation.
- bool PullStart() override {
+ bool PullStart(float, float) override {
started_ = true;
return true;
}
- void PullUpdate(float delta) override { delta_ += delta; }
+ void PullUpdate(float x_delta, float y_delta) override { delta_ += y_delta; }
void PullRelease(bool allow_refresh) override {
released_ = true;
diff --git a/chromium/ui/android/resources/resource_factory.cc b/chromium/ui/android/resources/resource_factory.cc
index 7a40a18e877..aa3221936d0 100644
--- a/chromium/ui/android/resources/resource_factory.cc
+++ b/chromium/ui/android/resources/resource_factory.cc
@@ -10,15 +10,12 @@ using base::android::JavaParamRef;
namespace ui {
-jlong JNI_ResourceFactory_CreateBitmapResource(
- JNIEnv* env,
- const JavaParamRef<jclass>& clazz) {
+jlong JNI_ResourceFactory_CreateBitmapResource(JNIEnv* env) {
return reinterpret_cast<intptr_t>(new Resource());
}
jlong JNI_ResourceFactory_CreateNinePatchBitmapResource(
JNIEnv* env,
- const JavaParamRef<jclass>& clazz,
jint padding_left,
jint padding_top,
jint padding_right,
diff --git a/chromium/ui/android/window_android.cc b/chromium/ui/android/window_android.cc
index aed6c8e4f61..5356c6de032 100644
--- a/chromium/ui/android/window_android.cc
+++ b/chromium/ui/android/window_android.cc
@@ -67,11 +67,13 @@ class WindowAndroid::WindowBeginFrameSource : public viz::BeginFrameSource {
class WindowAndroid::ScopedOnBeginFrame {
public:
- explicit ScopedOnBeginFrame(WindowAndroid::WindowBeginFrameSource* bfs);
+ explicit ScopedOnBeginFrame(WindowAndroid::WindowBeginFrameSource* bfs,
+ bool allow_reentrancy);
~ScopedOnBeginFrame();
private:
WindowAndroid::WindowBeginFrameSource* const begin_frame_source_;
+ const bool reentrant_;
std::vector<base::OnceClosure> vsync_complete_callbacks_;
};
@@ -100,7 +102,7 @@ void WindowAndroid::WindowBeginFrameSource::AddObserver(
// BeginFrames.
last_begin_frame_args_.deadline =
base::TimeTicks::Now() + last_begin_frame_args_.interval;
- ScopedOnBeginFrame scope(this);
+ ScopedOnBeginFrame scope(this, true /* allow_reentrancy */);
obs->OnBeginFrame(last_begin_frame_args_);
}
}
@@ -118,7 +120,7 @@ void WindowAndroid::WindowBeginFrameSource::RemoveObserver(
}
void WindowAndroid::WindowBeginFrameSource::OnGpuNoLongerBusy() {
- ScopedOnBeginFrame scope(this);
+ ScopedOnBeginFrame scope(this, false /* allow_reentrancy */);
for (auto& obs : observers_)
obs.OnBeginFrame(last_begin_frame_args_);
}
@@ -151,14 +153,26 @@ void WindowAndroid::WindowBeginFrameSource::AddBeginFrameCompletionCallback(
}
WindowAndroid::ScopedOnBeginFrame::ScopedOnBeginFrame(
- WindowAndroid::WindowBeginFrameSource* bfs)
- : begin_frame_source_(bfs) {
+ WindowAndroid::WindowBeginFrameSource* bfs,
+ bool allow_reentrancy)
+ : begin_frame_source_(bfs),
+ reentrant_(allow_reentrancy &&
+ begin_frame_source_->vsync_complete_callbacks_ptr_) {
+ if (reentrant_) {
+ DCHECK(begin_frame_source_->vsync_complete_callbacks_ptr_);
+ return;
+ }
DCHECK(!begin_frame_source_->vsync_complete_callbacks_ptr_);
begin_frame_source_->vsync_complete_callbacks_ptr_ =
&vsync_complete_callbacks_;
}
WindowAndroid::ScopedOnBeginFrame::~ScopedOnBeginFrame() {
+ if (reentrant_) {
+ DCHECK_NE(&vsync_complete_callbacks_,
+ begin_frame_source_->vsync_complete_callbacks_ptr_);
+ return;
+ }
DCHECK_EQ(&vsync_complete_callbacks_,
begin_frame_source_->vsync_complete_callbacks_ptr_);
begin_frame_source_->vsync_complete_callbacks_ptr_ = nullptr;
diff --git a/chromium/ui/aura/BUILD.gn b/chromium/ui/aura/BUILD.gn
index b02ca41ac97..5250b58d048 100644
--- a/chromium/ui/aura/BUILD.gn
+++ b/chromium/ui/aura/BUILD.gn
@@ -38,6 +38,7 @@ jumbo_component("aura") {
"local/window_port_local.h",
"mus/capture_synchronizer.h",
"mus/capture_synchronizer_delegate.h",
+ "mus/client_side_window_move_handler.h",
"mus/client_surface_embedder.h",
"mus/drag_drop_controller_host.h",
"mus/drag_drop_controller_mus.h",
@@ -79,6 +80,7 @@ jumbo_component("aura") {
"window_event_dispatcher.h",
"window_event_dispatcher_observer.h",
"window_observer.h",
+ "window_occlusion_change_builder.h",
"window_occlusion_tracker.h",
"window_port.h",
"window_targeter.h",
@@ -114,6 +116,7 @@ jumbo_component("aura") {
"mouse_location_manager.cc",
"mouse_location_manager.h",
"mus/capture_synchronizer.cc",
+ "mus/client_side_window_move_handler.cc",
"mus/client_surface_embedder.cc",
"mus/drag_drop_controller_mus.cc",
"mus/embed_root.cc",
@@ -123,6 +126,8 @@ jumbo_component("aura") {
"mus/in_flight_change.cc",
"mus/input_method_mus.cc",
"mus/mus_context_factory.cc",
+ "mus/mus_lsi_allocator.cc",
+ "mus/mus_lsi_allocator.h",
"mus/mus_mouse_location_updater.cc",
"mus/os_exchange_data_provider_mus.cc",
"mus/property_converter.cc",
@@ -146,6 +151,7 @@ jumbo_component("aura") {
"window_delegate.cc",
"window_event_dispatcher.cc",
"window_observer.cc",
+ "window_occlusion_change_builder.cc",
"window_occlusion_tracker.cc",
"window_port.cc",
"window_port_for_shutdown.cc",
@@ -159,6 +165,7 @@ jumbo_component("aura") {
friend = [
":aura_interactive_ui_tests",
":aura_unittests",
+ ":test_support",
]
defines = [ "AURA_IMPLEMENTATION" ]
@@ -184,6 +191,7 @@ jumbo_component("aura") {
"//services/ws/public/mojom",
"//skia",
"//ui/base",
+ "//ui/base/clipboard",
"//ui/base/ime",
"//ui/display",
"//ui/events",
@@ -297,8 +305,8 @@ jumbo_static_library("test_support") {
":aura",
"//services/ws/common",
- # Must be public as headers include ui_features.h.
- "//ui/base:ui_features",
+ # Must be public as headers include buildflags.h.
+ "//ui/base:buildflags",
]
deps = [
"//base/test:test_support",
@@ -379,7 +387,6 @@ executable("demo") {
test("aura_unittests") {
sources = [
"../compositor_extra/shadow_unittest.cc",
- "//ui/aura_extra/window_occlusion_impl_unittest_win.cc",
"gestures/gesture_recognizer_unittest.cc",
"mouse_location_manager_unittest.cc",
"mus/drag_drop_controller_mus_unittest.cc",
@@ -395,6 +402,7 @@ test("aura_unittests") {
"test/aura_test_suite.h",
"test/run_all_unittests.cc",
"window_event_dispatcher_unittest.cc",
+ "window_occlusion_change_builder_unittest.cc",
"window_occlusion_tracker_unittest.cc",
"window_targeter_unittest.cc",
"window_tree_host_unittest.cc",
@@ -417,7 +425,9 @@ test("aura_unittests") {
"//skia",
"//testing/gtest",
"//ui/aura_extra",
+ "//ui/aura_extra:tests",
"//ui/base:test_support",
+ "//ui/base/clipboard:clipboard_types",
"//ui/compositor:test_support",
"//ui/compositor_extra",
"//ui/display:test_support",
diff --git a/chromium/ui/aura/client/aura_constants.cc b/chromium/ui/aura/client/aura_constants.cc
index eaa411d6119..afc117d0bf2 100644
--- a/chromium/ui/aura/client/aura_constants.cc
+++ b/chromium/ui/aura/client/aura_constants.cc
@@ -14,6 +14,7 @@ DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, base::UnguessableToken*)
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, base::string16*)
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, ui::ModalType)
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, gfx::ImageSkia*)
+DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, gfx::NativeViewAccessible);
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, gfx::Rect*)
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, gfx::Size*)
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, gfx::SizeF*)
@@ -26,6 +27,7 @@ DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, int32_t)
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, int64_t)
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, aura::client::FocusClient*)
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, aura::Window*)
+DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT, std::vector<aura::Window*>*)
namespace aura {
namespace client {
@@ -50,11 +52,17 @@ 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_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kMaximumSize, nullptr);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kMinimumSize, nullptr);
-DEFINE_UI_CLASS_PROPERTY_KEY(bool, kMirroringEnabledKey, false);
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::vector<Window*>,
+ kMirrorWindowList,
+ nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kChildModalParentKey, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(ui::ModalType, kModalKey, ui::MODAL_TYPE_NONE);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kNameKey, nullptr);
+DEFINE_UI_CLASS_PROPERTY_KEY(gfx::NativeViewAccessible,
+ kParentNativeViewAccessibleKey,
+ nullptr);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kPreferredSize, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(
ui::WindowShowState, kPreMinimizedShowStateKey, ui::SHOW_STATE_DEFAULT);
diff --git a/chromium/ui/aura/client/aura_constants.h b/chromium/ui/aura/client/aura_constants.h
index 8692e29d58d..b142ac2cdc0 100644
--- a/chromium/ui/aura/client/aura_constants.h
+++ b/chromium/ui/aura/client/aura_constants.h
@@ -6,6 +6,7 @@
#define UI_AURA_CLIENT_AURA_CONSTANTS_H_
#include <string>
+#include <vector>
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -85,12 +86,16 @@ 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 store the maximum size of the window.
+AURA_EXPORT extern const WindowProperty<gfx::Size*>* const kMaximumSize;
+
// A property key to store the minimum size of the window.
AURA_EXPORT extern const WindowProperty<gfx::Size*>* const kMinimumSize;
-// A property key to indicate that a window is being "mirrored" and its contents
-// should render regardless of its actual visibility state.
-AURA_EXPORT extern const WindowProperty<bool>* const kMirroringEnabledKey;
+// A property key to store a list of windows showing a mirror of the window this
+// property is set on.
+AURA_EXPORT extern const WindowProperty<std::vector<Window*>*>* const
+ kMirrorWindowList;
// The modal parent of a child modal window.
AURA_EXPORT extern const WindowProperty<Window*>* const kChildModalParentKey;
@@ -101,6 +106,12 @@ AURA_EXPORT extern const WindowProperty<ui::ModalType>* const kModalKey;
// A property key to store the name of the window; mostly used for debugging.
AURA_EXPORT extern const WindowProperty<std::string*>* const kNameKey;
+// A property key to store the accessible parent of a native view. This is
+// used to allow WebContents to access their accessible parents for use in
+// walking up the accessibility tree via platform APIs.
+AURA_EXPORT extern const aura::WindowProperty<gfx::NativeViewAccessible>* const
+ kParentNativeViewAccessibleKey;
+
// A property key to store the preferred size of the window.
AURA_EXPORT extern const WindowProperty<gfx::Size*>* const kPreferredSize;
diff --git a/chromium/ui/aura/client/drag_drop_delegate.cc b/chromium/ui/aura/client/drag_drop_delegate.cc
index 361a6f023fe..c273606c994 100644
--- a/chromium/ui/aura/client/drag_drop_delegate.cc
+++ b/chromium/ui/aura/client/drag_drop_delegate.cc
@@ -4,17 +4,15 @@
#include "ui/aura/client/drag_drop_delegate.h"
-#include "ui/aura/window.h"
#include "ui/base/class_property.h"
-DEFINE_UI_CLASS_PROPERTY_TYPE(aura::client::DragDropDelegate*)
+DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT,
+ aura::client::DragDropDelegate*)
namespace aura {
namespace client {
-DEFINE_LOCAL_UI_CLASS_PROPERTY_KEY(DragDropDelegate*,
- kDragDropDelegateKey,
- nullptr);
+DEFINE_UI_CLASS_PROPERTY_KEY(DragDropDelegate*, kDragDropDelegateKey, nullptr);
void SetDragDropDelegate(Window* window, DragDropDelegate* delegate) {
window->SetProperty(kDragDropDelegateKey, delegate);
diff --git a/chromium/ui/aura/client/drag_drop_delegate.h b/chromium/ui/aura/client/drag_drop_delegate.h
index dde7f32ec73..03104337852 100644
--- a/chromium/ui/aura/client/drag_drop_delegate.h
+++ b/chromium/ui/aura/client/drag_drop_delegate.h
@@ -6,6 +6,7 @@
#define UI_AURA_CLIENT_DRAG_DROP_DELEGATE_H_
#include "ui/aura/aura_export.h"
+#include "ui/aura/window.h"
namespace ui {
class DropTargetEvent;
@@ -45,6 +46,9 @@ AURA_EXPORT void SetDragDropDelegate(Window* window,
DragDropDelegate* delegate);
AURA_EXPORT DragDropDelegate* GetDragDropDelegate(Window* window);
+AURA_EXPORT extern const WindowProperty<DragDropDelegate*>* const
+ kDragDropDelegateKey;
+
} // namespace client
} // namespace aura
diff --git a/chromium/ui/aura/client/window_types.h b/chromium/ui/aura/client/window_types.h
index 42789226fd1..261fc3ff9df 100644
--- a/chromium/ui/aura/client/window_types.h
+++ b/chromium/ui/aura/client/window_types.h
@@ -22,9 +22,6 @@ enum WindowType {
// A window intended as a control. Not laid out by the shell.
WINDOW_TYPE_CONTROL,
- // Always on top windows aligned to bottom right of screen.
- WINDOW_TYPE_PANEL,
-
WINDOW_TYPE_MENU,
WINDOW_TYPE_TOOLTIP,
diff --git a/chromium/ui/aura/demo/demo_main.cc b/chromium/ui/aura/demo/demo_main.cc
index ce82f5b72d3..0282ea55ca1 100644
--- a/chromium/ui/aura/demo/demo_main.cc
+++ b/chromium/ui/aura/demo/demo_main.cc
@@ -92,7 +92,7 @@ class DemoWindowDelegate : public aura::WindowDelegate {
void OnWindowDestroyed(aura::Window* window) override {}
void OnWindowTargetVisibilityChanged(bool visible) override {}
bool HasHitTestMask() const override { return false; }
- void GetHitTestMask(gfx::Path* mask) const override {}
+ void GetHitTestMask(SkPath* mask) const override {}
private:
SkColor color_;
diff --git a/chromium/ui/aura/env.h b/chromium/ui/aura/env.h
index bf5499700d8..03cd3df8e16 100644
--- a/chromium/ui/aura/env.h
+++ b/chromium/ui/aura/env.h
@@ -73,7 +73,7 @@ class AURA_EXPORT Env : public ui::EventTarget,
public base::SupportsUserData {
public:
enum class Mode {
- // Classic aura.
+ // Classic aura, or ash under SingleProcessMash.
LOCAL,
// Aura with a backend of mus.
diff --git a/chromium/ui/aura/mus/client_side_window_move_handler.cc b/chromium/ui/aura/mus/client_side_window_move_handler.cc
new file mode 100644
index 00000000000..bc37be5fbdb
--- /dev/null
+++ b/chromium/ui/aura/mus/client_side_window_move_handler.cc
@@ -0,0 +1,115 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/mus/client_side_window_move_handler.h"
+
+#include "base/bind.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/mus/window_tree_host_mus.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/base/hit_test.h"
+#include "ui/events/event.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+
+namespace aura {
+
+namespace {
+
+void WindowMoveEnded(Window* window, bool success) {
+ window->env()->gesture_recognizer()->CancelActiveTouches(window);
+}
+
+} // namespace
+
+ClientSideWindowMoveHandler::ClientSideWindowMoveHandler(Env* env) : env_(env) {
+ env_->AddPreTargetHandler(this);
+}
+
+ClientSideWindowMoveHandler::~ClientSideWindowMoveHandler() {
+ env_->RemovePreTargetHandler(this);
+}
+
+void ClientSideWindowMoveHandler::MaybeSetupLastTarget(
+ ui::LocatedEvent* event) {
+ last_target_.RemoveAll();
+ Window* window = static_cast<Window*>(event->target());
+ if (!window || !window->delegate())
+ return;
+ int component = window->delegate()->GetNonClientComponent(event->location());
+
+ // TODO(mukai): add the support of window resizing components like HTTOP.
+ if (component != HTCAPTION)
+ return;
+
+ last_target_.Add(window);
+ last_location_ = event->location();
+}
+
+void ClientSideWindowMoveHandler::MaybePerformWindowMove(
+ ui::LocatedEvent* event,
+ ws::mojom::MoveLoopSource source) {
+ Window* target = static_cast<Window*>(event->target());
+ if (!target || !last_target_.Contains(target) || !target->delegate())
+ return;
+
+ gfx::Point screen_location = last_location_;
+ aura::client::GetScreenPositionClient(target->GetRootWindow())
+ ->ConvertPointToScreen(target, &screen_location);
+ WindowTreeHostMus::ForWindow(target)->PerformWindowMove(
+ target, source, screen_location,
+ base::BindOnce(&WindowMoveEnded, target));
+
+ // Clear |last_target_| so that event->target() won't match with
+ // |last_target_| anymore.
+ last_target_.RemoveAll();
+ event->SetHandled();
+}
+
+void ClientSideWindowMoveHandler::OnMouseEvent(ui::MouseEvent* event) {
+ // The logic here should be aligned with ash::WmToplevelWindowEventHandler.
+ // TODO(mukai): create a common class in ash/public/cpp to share the logic.
+ if (event->handled())
+ return;
+ if ((event->flags() &
+ (ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON)) != 0) {
+ return;
+ }
+ switch (event->type()) {
+ case ui::ET_MOUSE_PRESSED:
+ MaybeSetupLastTarget(event);
+ break;
+
+ case ui::ET_MOUSE_DRAGGED:
+ MaybePerformWindowMove(event, ws::mojom::MoveLoopSource::MOUSE);
+ break;
+
+ default:
+ // Do nothing.
+ break;
+ }
+}
+
+void ClientSideWindowMoveHandler::OnGestureEvent(ui::GestureEvent* event) {
+ // The logic here should be aligned with ash::WmToplevelWindowEventHandler.
+ // TODO(mukai): create a common class in ash/public/cpp to share the logic.
+ if (event->handled())
+ return;
+ switch (event->type()) {
+ case ui::ET_GESTURE_TAP_DOWN:
+ MaybeSetupLastTarget(event);
+ return;
+
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ MaybePerformWindowMove(event, ws::mojom::MoveLoopSource::TOUCH);
+ break;
+
+ default:
+ // Do nothing.
+ break;
+ }
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/mus/client_side_window_move_handler.h b/chromium/ui/aura/mus/client_side_window_move_handler.h
new file mode 100644
index 00000000000..c1cbb410470
--- /dev/null
+++ b/chromium/ui/aura/mus/client_side_window_move_handler.h
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_MUS_CLIENT_SIDE_WINDOW_MOVE_HANDLER_H_
+#define UI_AURA_MUS_CLIENT_SIDE_WINDOW_MOVE_HANDLER_H_
+
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/events/event_handler.h"
+
+namespace ui {
+class LocatedEvent;
+}
+
+namespace aura {
+
+class Env;
+
+// ClientSideWindowMoveHandler handles mouse/gesture events and performs the
+// window move session when the event is located on draggable area.
+class ClientSideWindowMoveHandler : public ui::EventHandler {
+ public:
+ explicit ClientSideWindowMoveHandler(Env* env);
+ ~ClientSideWindowMoveHandler() override;
+
+ private:
+ // Setup |last_target_| and |last_location_| for |event|, or clear them when
+ // the event will not involve window move.
+ void MaybeSetupLastTarget(ui::LocatedEvent* event);
+
+ // Conduct the window move.
+ void MaybePerformWindowMove(ui::LocatedEvent* event,
+ ws::mojom::MoveLoopSource source);
+
+ // ui::EventHandler:
+ void OnMouseEvent(ui::MouseEvent* event) override;
+ void OnGestureEvent(ui::GestureEvent* event) override;
+
+ Env* env_;
+ WindowTracker last_target_;
+ gfx::Point last_location_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientSideWindowMoveHandler);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_MUS_CLIENT_SIDE_WINDOW_MOVE_HANDLER_H_
diff --git a/chromium/ui/aura/mus/client_surface_embedder.cc b/chromium/ui/aura/mus/client_surface_embedder.cc
index 5c33f34c7fa..d00bdcf1612 100644
--- a/chromium/ui/aura/mus/client_surface_embedder.cc
+++ b/chromium/ui/aura/mus/client_surface_embedder.cc
@@ -20,6 +20,7 @@ ClientSurfaceEmbedder::ClientSurfaceEmbedder(
std::make_unique<ui::Layer>(ui::LAYER_TEXTURED))),
inject_gutter_(inject_gutter),
client_area_insets_(client_area_insets) {
+ surface_layer_owner_->layer()->set_name("ClientSurfaceEmbedder");
surface_layer_owner_->layer()->SetMasksToBounds(true);
// The frame provided by the parent window->layer() needs to show through
// the surface layer.
diff --git a/chromium/ui/aura/mus/drag_drop_controller_mus.cc b/chromium/ui/aura/mus/drag_drop_controller_mus.cc
index 9670df44ac9..719abb1d058 100644
--- a/chromium/ui/aura/mus/drag_drop_controller_mus.cc
+++ b/chromium/ui/aura/mus/drag_drop_controller_mus.cc
@@ -75,17 +75,19 @@ void DragDropControllerMus::OnDragDropStart(
uint32_t DragDropControllerMus::OnDragEnter(WindowMus* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask) {
- return HandleDragEnterOrOver(window, event_flags, screen_location,
+ return HandleDragEnterOrOver(window, event_flags, location_in_root, location,
effect_bitmask, true);
}
uint32_t DragDropControllerMus::OnDragOver(WindowMus* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask) {
- return HandleDragEnterOrOver(window, event_flags, screen_location,
+ return HandleDragEnterOrOver(window, event_flags, location_in_root, location,
effect_bitmask, false);
}
@@ -101,7 +103,8 @@ void DragDropControllerMus::OnDragLeave(WindowMus* window) {
uint32_t DragDropControllerMus::OnCompleteDrop(
WindowMus* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask) {
if (drop_target_window_tracker_.windows().empty())
return ws::mojom::kDropEffectNone;
@@ -109,8 +112,9 @@ uint32_t DragDropControllerMus::OnCompleteDrop(
DCHECK(window);
Window* current_target = drop_target_window_tracker_.Pop();
DCHECK_EQ(window->GetWindow(), current_target);
- std::unique_ptr<ui::DropTargetEvent> event = CreateDropTargetEvent(
- window->GetWindow(), event_flags, screen_location, effect_bitmask);
+ std::unique_ptr<ui::DropTargetEvent> event =
+ CreateDropTargetEvent(window->GetWindow(), event_flags, location_in_root,
+ location, effect_bitmask);
return client::GetDragDropDelegate(current_target)->OnPerformDrop(*event);
}
@@ -193,7 +197,8 @@ void DragDropControllerMus::RemoveObserver(
uint32_t DragDropControllerMus::HandleDragEnterOrOver(
WindowMus* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask,
bool is_enter) {
client::DragDropDelegate* drag_drop_delegate =
@@ -207,28 +212,26 @@ uint32_t DragDropControllerMus::HandleDragEnterOrOver(
}
drop_target_window_tracker_.Add(window->GetWindow());
- std::unique_ptr<ui::DropTargetEvent> event = CreateDropTargetEvent(
- window->GetWindow(), event_flags, screen_location, effect_bitmask);
+ std::unique_ptr<ui::DropTargetEvent> event =
+ CreateDropTargetEvent(window->GetWindow(), event_flags, location_in_root,
+ location, effect_bitmask);
if (is_enter)
drag_drop_delegate->OnDragEntered(*event);
return drag_drop_delegate->OnDragUpdated(*event);
}
std::unique_ptr<ui::DropTargetEvent>
-DragDropControllerMus::CreateDropTargetEvent(Window* window,
- uint32_t event_flags,
- const gfx::Point& screen_location,
- uint32_t effect_bitmask) {
- DCHECK(window->GetHost());
- gfx::Point root_location = screen_location;
- window->GetHost()->ConvertScreenInPixelsToDIP(&root_location);
- gfx::PointF location(root_location);
- Window::ConvertPointToTarget(window->GetRootWindow(), window, &location);
+DragDropControllerMus::CreateDropTargetEvent(
+ Window* window,
+ uint32_t event_flags,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
+ uint32_t effect_bitmask) {
std::unique_ptr<ui::DropTargetEvent> event =
std::make_unique<ui::DropTargetEvent>(
current_drag_state_ ? current_drag_state_->drag_data
: *(os_exchange_data_.get()),
- location, gfx::PointF(root_location), effect_bitmask);
+ location, location_in_root, effect_bitmask);
event->set_flags(event_flags);
ui::Event::DispatcherApi(event.get()).set_target(window);
return event;
diff --git a/chromium/ui/aura/mus/drag_drop_controller_mus.h b/chromium/ui/aura/mus/drag_drop_controller_mus.h
index 0bcb808a73f..cc95f6089d4 100644
--- a/chromium/ui/aura/mus/drag_drop_controller_mus.h
+++ b/chromium/ui/aura/mus/drag_drop_controller_mus.h
@@ -17,6 +17,10 @@
#include "ui/aura/window_tracker.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+namespace gfx {
+class PointF;
+}
+
namespace ws {
namespace mojom {
class WindowTree;
@@ -51,16 +55,19 @@ class AURA_EXPORT DragDropControllerMus : public client::DragDropClient {
void OnDragDropStart(std::map<std::string, std::vector<uint8_t>> data);
uint32_t OnDragEnter(WindowMus* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask);
uint32_t OnDragOver(WindowMus* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask);
void OnDragLeave(WindowMus* window);
uint32_t OnCompleteDrop(WindowMus* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask);
void OnPerformDragDropCompleted(uint32_t action_taken);
void OnDragDropDone();
@@ -83,14 +90,16 @@ class AURA_EXPORT DragDropControllerMus : public client::DragDropClient {
// Called from OnDragEnter() and OnDragOver().
uint32_t HandleDragEnterOrOver(WindowMus* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask,
bool is_enter);
std::unique_ptr<ui::DropTargetEvent> CreateDropTargetEvent(
Window* window,
uint32_t event_flags,
- const gfx::Point& screen_location,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask);
DragDropControllerHost* drag_drop_controller_host_;
diff --git a/chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc b/chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc
index 753d7c9d3ba..a48bd08f7ad 100644
--- a/chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc
+++ b/chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc
@@ -64,9 +64,10 @@ class DragDropControllerMusTest : public test::AuraMusClientTestBase {
private:
void DragMoveAndDrop() {
WindowMus* const window_mus = WindowMus::Get(window_.get());
- controller_->OnDragEnter(window_mus, 0, gfx::Point(5, 20), 0);
- controller_->OnDragOver(window_mus, 0, gfx::Point(5, 20), 0);
- controller_->OnCompleteDrop(window_mus, 0, gfx::Point(5, 20), 0);
+ const gfx::PointF point(5, 20);
+ controller_->OnDragEnter(window_mus, 0, point, point, 0);
+ controller_->OnDragOver(window_mus, 0, point, point, 0);
+ controller_->OnCompleteDrop(window_mus, 0, point, point, 0);
controller_->OnPerformDragDropCompleted(0);
}
diff --git a/chromium/ui/aura/mus/focus_synchronizer_unittest.cc b/chromium/ui/aura/mus/focus_synchronizer_unittest.cc
index 08eb3467486..83feb7dfe39 100644
--- a/chromium/ui/aura/mus/focus_synchronizer_unittest.cc
+++ b/chromium/ui/aura/mus/focus_synchronizer_unittest.cc
@@ -24,8 +24,10 @@ class TestFocusRules : public wm::BaseFocusRules {
~TestFocusRules() override = default;
// wm::BaseFocusRules overrides:
- bool SupportsChildActivation(Window* window) const override { return true; }
- bool CanActivateWindow(Window* window) const override { return true; }
+ bool SupportsChildActivation(const Window* window) const override {
+ return true;
+ }
+ bool CanActivateWindow(const Window* window) const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(TestFocusRules);
diff --git a/chromium/ui/aura/mus/in_flight_change.cc b/chromium/ui/aura/mus/in_flight_change.cc
index fe5ed3153b7..9d6333fdef3 100644
--- a/chromium/ui/aura/mus/in_flight_change.cc
+++ b/chromium/ui/aura/mus/in_flight_change.cc
@@ -145,7 +145,10 @@ void CrashInFlightChange::SetRevertValueFrom(const InFlightChange& change) {
}
void CrashInFlightChange::ChangeFailed() {
- CHECK(false) << "change failed, type=" << static_cast<int>(change_type());
+ // TODO(crbug.com/912228): remove LOG(). Used to figure out why this is being
+ // hit.
+ LOG(ERROR) << "change failed, type=" << static_cast<int>(change_type());
+ CHECK(false);
}
void CrashInFlightChange::Revert() {
@@ -250,7 +253,7 @@ void InFlightPropertyChange::Revert() {
// InFlightCursorChange ----------------------------------------------------
InFlightCursorChange::InFlightCursorChange(WindowMus* window,
- const ui::CursorData& revert_value)
+ const ui::Cursor& revert_value)
: InFlightChange(window, ChangeType::CURSOR),
revert_cursor_(revert_value) {}
diff --git a/chromium/ui/aura/mus/in_flight_change.h b/chromium/ui/aura/mus/in_flight_change.h
index bfb8761a3b7..1d6d0f630bd 100644
--- a/chromium/ui/aura/mus/in_flight_change.h
+++ b/chromium/ui/aura/mus/in_flight_change.h
@@ -16,7 +16,7 @@
#include "base/optional.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "ui/aura/window_observer.h"
-#include "ui/base/cursor/cursor_data.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/transform.h"
@@ -296,7 +296,7 @@ class InFlightPropertyChange : public InFlightChange {
class InFlightCursorChange : public InFlightChange {
public:
- InFlightCursorChange(WindowMus* window, const ui::CursorData& revert_value);
+ InFlightCursorChange(WindowMus* window, const ui::Cursor& revert_value);
~InFlightCursorChange() override;
// InFlightChange:
@@ -304,7 +304,7 @@ class InFlightCursorChange : public InFlightChange {
void Revert() override;
private:
- ui::CursorData revert_cursor_;
+ ui::Cursor revert_cursor_;
DISALLOW_COPY_AND_ASSIGN(InFlightCursorChange);
};
diff --git a/chromium/ui/aura/mus/input_method_mus.cc b/chromium/ui/aura/mus/input_method_mus.cc
index 9a1d3c19ebe..589fc814538 100644
--- a/chromium/ui/aura/mus/input_method_mus.cc
+++ b/chromium/ui/aura/mus/input_method_mus.cc
@@ -102,8 +102,13 @@ void InputMethodMus::OnTextInputTypeChanged(const ui::TextInputClient* client) {
UpdateTextInputType();
- if (input_method_)
- input_method_->OnTextInputTypeChanged(client->GetTextInputType());
+ if (!input_method_)
+ return;
+
+ auto text_input_state = ws::mojom::TextInputState::New(
+ client->GetTextInputType(), client->GetTextInputMode(),
+ client->GetTextDirection(), client->GetTextInputFlags());
+ input_method_->OnTextInputStateChanged(std::move(text_input_state));
}
void InputMethodMus::OnCaretBoundsChanged(const ui::TextInputClient* client) {
@@ -188,18 +193,15 @@ void InputMethodMus::OnDidChangeFocusedClient(
std::make_unique<TextInputClientImpl>(focused, delegate());
if (ime_driver_) {
- ws::mojom::StartSessionDetailsPtr details =
- ws::mojom::StartSessionDetails::New();
- details->client =
- text_input_client_->CreateInterfacePtrAndBind().PassInterface();
- details->input_method_request = MakeRequest(&input_method_ptr_);
- input_method_ = input_method_ptr_.get();
- details->text_input_type = focused->GetTextInputType();
- details->text_input_mode = focused->GetTextInputMode();
- details->text_direction = focused->GetTextDirection();
- details->text_input_flags = focused->GetTextInputFlags();
+ ws::mojom::SessionDetailsPtr details = ws::mojom::SessionDetails::New();
+ details->state = ws::mojom::TextInputState::New(
+ focused->GetTextInputType(), focused->GetTextInputMode(),
+ focused->GetTextDirection(), focused->GetTextInputFlags());
details->caret_bounds = focused->GetCaretBounds();
- ime_driver_->StartSession(std::move(details));
+ ime_driver_->StartSession(MakeRequest(&input_method_ptr_),
+ text_input_client_->CreateInterfacePtrAndBind(),
+ std::move(details));
+ input_method_ = input_method_ptr_.get();
}
}
diff --git a/chromium/ui/aura/mus/input_method_mus_unittest.cc b/chromium/ui/aura/mus/input_method_mus_unittest.cc
index b70f26395ba..7657e3d1080 100644
--- a/chromium/ui/aura/mus/input_method_mus_unittest.cc
+++ b/chromium/ui/aura/mus/input_method_mus_unittest.cc
@@ -56,8 +56,9 @@ class TestInputMethod : public ws::mojom::InputMethod {
}
// ui::ime::InputMethod:
- void OnTextInputTypeChanged(ui::TextInputType text_input_type) override {
- was_on_text_input_type_changed_called_ = true;
+ void OnTextInputStateChanged(
+ ws::mojom::TextInputStatePtr text_input_state) override {
+ was_on_text_input_state_changed_called_ = true;
}
void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) override {
was_on_caret_bounds_changed_called_ = true;
@@ -71,8 +72,8 @@ class TestInputMethod : public ws::mojom::InputMethod {
was_show_virtual_keyboard_if_enabled_called_ = true;
}
- bool was_on_text_input_type_changed_called() {
- return was_on_text_input_type_changed_called_;
+ bool was_on_text_input_state_changed_called() {
+ return was_on_text_input_state_changed_called_;
}
bool was_on_caret_bounds_changed_called() {
@@ -88,7 +89,7 @@ class TestInputMethod : public ws::mojom::InputMethod {
}
private:
- bool was_on_text_input_type_changed_called_ = false;
+ bool was_on_text_input_state_changed_called_ = false;
bool was_on_caret_bounds_changed_called_ = false;
bool was_cancel_composition_called_ = false;
bool was_show_virtual_keyboard_if_enabled_called_ = false;
@@ -294,7 +295,7 @@ TEST_F(InputMethodMusTest, ChangeTextInputTypeFromUnfocusedClient) {
InputMethodMusTestApi::CallOnTextInputTypeChanged(&input_method_mus,
&unfocused_input_client);
- EXPECT_FALSE(test_input_method.was_on_text_input_type_changed_called());
+ EXPECT_FALSE(test_input_method.was_on_text_input_state_changed_called());
}
// Calling OnCaretBoundsChanged from unfocused client should
diff --git a/chromium/ui/aura/mus/mus_context_factory.cc b/chromium/ui/aura/mus/mus_context_factory.cc
index eef0df5d05a..eff69071a56 100644
--- a/chromium/ui/aura/mus/mus_context_factory.cc
+++ b/chromium/ui/aura/mus/mus_context_factory.cc
@@ -39,7 +39,12 @@ void MusContextFactory::OnEstablishedGpuChannel(
WindowTreeHost* host =
WindowTreeHost::GetForAcceleratedWidget(compositor->widget());
WindowPortMus* window_port = WindowPortMus::Get(host->window());
- DCHECK(window_port);
+ // There should always be a WindowPortMus for WindowTreeHost::window(). If
+ // there isn't, it likely means we got the wrong WindowTreeHost.
+ //
+ // TODO(sky): make Compositor extend SupportsUserData so that this code
+ // doesn't need to use GetForAcceleratedWidget().
+ CHECK(window_port);
scoped_refptr<viz::ContextProvider> context_provider =
gpu_->CreateContextProvider(gpu_channel);
diff --git a/chromium/ui/aura/mus/mus_lsi_allocator.cc b/chromium/ui/aura/mus/mus_lsi_allocator.cc
new file mode 100644
index 00000000000..4c6da346761
--- /dev/null
+++ b/chromium/ui/aura/mus/mus_lsi_allocator.cc
@@ -0,0 +1,115 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/mus/mus_lsi_allocator.h"
+
+#include <utility>
+
+#include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "ui/aura/mus/client_surface_embedder.h"
+#include "ui/aura/mus/window_port_mus.h"
+#include "ui/aura/mus/window_tree_client.h"
+
+namespace aura {
+
+ParentAllocator::ParentAllocator(MusLsiAllocatorType type,
+ WindowPortMus* window,
+ WindowTreeClient* window_tree_client)
+ : MusLsiAllocator(type),
+ window_(window),
+ window_tree_client_(window_tree_client) {
+ DCHECK(window_);
+ DCHECK(window_tree_client_);
+ if (type == MusLsiAllocatorType::kEmbed) {
+ client_surface_embedder_ = std::make_unique<ClientSurfaceEmbedder>(
+ GetWindow(), /* inject_gutter */ false, gfx::Insets());
+ }
+}
+
+ParentAllocator::~ParentAllocator() = default;
+
+void ParentAllocator::AllocateLocalSurfaceId() {
+ last_surface_size_in_pixels_ = window_->GetSizeInPixels();
+ parent_local_surface_id_allocator_.GenerateId();
+ Update(/* send_bounds_change */ true);
+}
+
+viz::ScopedSurfaceIdAllocator ParentAllocator::GetSurfaceIdAllocator(
+ base::OnceClosure allocation_task) {
+ return viz::ScopedSurfaceIdAllocator(&parent_local_surface_id_allocator_,
+ std::move(allocation_task));
+}
+
+void ParentAllocator::InvalidateLocalSurfaceId() {
+ parent_local_surface_id_allocator_.Invalidate();
+}
+
+void ParentAllocator::UpdateLocalSurfaceIdFromEmbeddedClient(
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) {
+ parent_local_surface_id_allocator_.UpdateFromChild(
+ embedded_client_local_surface_id_allocation);
+ // Ensure there is a valid value.
+ if (!GetLocalSurfaceIdAllocation().IsValid())
+ parent_local_surface_id_allocator_.GenerateId();
+ Update(/* send_bounds_change */ true);
+}
+
+void ParentAllocator::OnDeviceScaleFactorChanged() {
+ parent_local_surface_id_allocator_.GenerateId();
+ Update(/* send_bounds_change */ true);
+}
+
+void ParentAllocator::OnDidChangeBounds(const gfx::Size& size_in_pixels,
+ bool from_server) {
+ if (last_surface_size_in_pixels_ == size_in_pixels &&
+ parent_local_surface_id_allocator_.HasValidLocalSurfaceIdAllocation()) {
+ return;
+ }
+
+ last_surface_size_in_pixels_ = size_in_pixels;
+ parent_local_surface_id_allocator_.GenerateId();
+ // If |from_server| is true, then WindowPortMus sends a bound change.
+ Update(/* send_bounds_change */ from_server);
+}
+
+const viz::LocalSurfaceIdAllocation&
+ParentAllocator::GetLocalSurfaceIdAllocation() {
+ return parent_local_surface_id_allocator_
+ .GetCurrentLocalSurfaceIdAllocation();
+}
+
+aura::Window* ParentAllocator::GetWindow() {
+ return static_cast<WindowMus*>(window_)->GetWindow();
+}
+
+void ParentAllocator::Update(bool send_bounds_change) {
+ // If not in a bounds change, then need to update server of new
+ // LocalSurfaceId.
+ if (send_bounds_change) {
+ const gfx::Rect& bounds = GetWindow()->bounds();
+ window_tree_client_->OnWindowMusBoundsChanged(window_, bounds, bounds);
+ }
+ if (GetWindow()->IsEmbeddingClient() && client_surface_embedder_) {
+ viz::SurfaceId surface_id(GetWindow()->GetFrameSinkId(),
+ GetLocalSurfaceIdAllocation().local_surface_id());
+ client_surface_embedder_->SetSurfaceId(surface_id);
+ client_surface_embedder_->UpdateSizeAndGutters();
+ }
+}
+
+void ParentAllocator::OnFrameSinkIdChanged() {
+ Update(/* send_bounds_change */ false);
+}
+
+// static
+std::unique_ptr<MusLsiAllocator> MusLsiAllocator::CreateAllocator(
+ MusLsiAllocatorType type,
+ WindowPortMus* window,
+ WindowTreeClient* window_tree_client) {
+ return std::make_unique<ParentAllocator>(type, window, window_tree_client);
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/mus/mus_lsi_allocator.h b/chromium/ui/aura/mus/mus_lsi_allocator.h
new file mode 100644
index 00000000000..73dc6e50c77
--- /dev/null
+++ b/chromium/ui/aura/mus/mus_lsi_allocator.h
@@ -0,0 +1,119 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_MUS_MUS_LSI_ALLOCATOR_H_
+#define UI_AURA_MUS_MUS_LSI_ALLOCATOR_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace viz {
+class LocalSurfaceIdAllocation;
+class ScopedSurfaceIdAllocator;
+} // namespace viz
+
+namespace aura {
+
+class ClientSurfaceEmbedder;
+class Window;
+class WindowPortMus;
+class WindowTreeClient;
+
+enum class MusLsiAllocatorType {
+ // The allocator was created by a window that has an embedding in it. This
+ // is the embedder side, *not* the embedding side.
+ kEmbed,
+
+ // A local window that has a FrameSinkId associated with it.
+ kLocal,
+};
+
+// MusLsiAllocator is used by WindowPortMus to handle management of
+// LocalSurfaceIdAllocation, and associated data.
+class MusLsiAllocator {
+ public:
+ virtual ~MusLsiAllocator() {}
+
+ static std::unique_ptr<MusLsiAllocator> CreateAllocator(
+ MusLsiAllocatorType type,
+ WindowPortMus* window,
+ WindowTreeClient* window_tree_client);
+
+ MusLsiAllocatorType type() const { return type_; }
+
+ virtual void AllocateLocalSurfaceId() = 0;
+ virtual viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
+ base::OnceClosure allocation_task) = 0;
+ virtual void InvalidateLocalSurfaceId() = 0;
+ virtual void UpdateLocalSurfaceIdFromEmbeddedClient(
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) = 0;
+ virtual void OnDeviceScaleFactorChanged() = 0;
+ virtual void OnDidChangeBounds(const gfx::Size& size_in_pixels,
+ bool from_server) = 0;
+ virtual const viz::LocalSurfaceIdAllocation&
+ GetLocalSurfaceIdAllocation() = 0;
+ virtual void OnFrameSinkIdChanged() = 0;
+
+ protected:
+ explicit MusLsiAllocator(MusLsiAllocatorType type) : type_(type) {}
+
+ private:
+ const MusLsiAllocatorType type_;
+};
+
+// ParentAllocator is used for kEmbed and kLocal types of allocators. It uses
+// a ParentLocalSurfaceIdAllocator to generate a LocalSurfaceIdAllocation.
+// Additionally ParenAllocator may creates a ClientSurfaceEmbedder| to handle
+// associating the FrameSinkId with Viz.
+//
+// This is an implementation detail and only public for tests to poke at.
+class ParentAllocator : public MusLsiAllocator {
+ public:
+ ParentAllocator(MusLsiAllocatorType type,
+ WindowPortMus* window,
+ WindowTreeClient* window_tree_client);
+ ~ParentAllocator() override;
+
+ // MusLsiAllocator:
+ void AllocateLocalSurfaceId() override;
+ viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
+ base::OnceClosure allocation_task) override;
+ void InvalidateLocalSurfaceId() override;
+ void UpdateLocalSurfaceIdFromEmbeddedClient(
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) override;
+ void OnDeviceScaleFactorChanged() override;
+ void OnDidChangeBounds(const gfx::Size& size_in_pixels,
+ bool from_server) override;
+ const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() override;
+ void OnFrameSinkIdChanged() override;
+
+ private:
+ friend class WindowPortMusTestHelper;
+
+ Window* GetWindow();
+
+ void Update(bool in_bounds_change);
+
+ WindowPortMus* window_;
+ WindowTreeClient* window_tree_client_;
+ viz::ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_;
+ std::unique_ptr<ClientSurfaceEmbedder> client_surface_embedder_;
+
+ // Last size (in pixels) that a LocalSurfaceId was generated for.
+ gfx::Size last_surface_size_in_pixels_;
+
+ DISALLOW_COPY_AND_ASSIGN(ParentAllocator);
+};
+} // namespace aura
+
+#endif // UI_AURA_MUS_MUS_LSI_ALLOCATOR_H_
diff --git a/chromium/ui/aura/mus/os_exchange_data_provider_mus.cc b/chromium/ui/aura/mus/os_exchange_data_provider_mus.cc
index f8e327cd09b..587516a4f86 100644
--- a/chromium/ui/aura/mus/os_exchange_data_provider_mus.cc
+++ b/chromium/ui/aura/mus/os_exchange_data_provider_mus.cc
@@ -15,6 +15,8 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/filename_util.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/mojo/clipboard.mojom.h"
#include "url/gurl.h"
@@ -87,8 +89,7 @@ void OSExchangeDataProviderMus::SetString(const base::string16& data) {
if (HasString())
return;
- mime_data_[ui::Clipboard::kMimeTypeText] =
- FromString(base::UTF16ToUTF8(data));
+ mime_data_[ui::kMimeTypeText] = FromString(base::UTF16ToUTF8(data));
}
void OSExchangeDataProviderMus::SetURL(const GURL& url,
@@ -98,10 +99,10 @@ void OSExchangeDataProviderMus::SetURL(const GURL& url,
AddString16ToVector(spec, &data);
AddString16ToVector(base::ASCIIToUTF16("\n"), &data);
AddString16ToVector(title, &data);
- mime_data_[ui::Clipboard::kMimeTypeMozillaURL] = std::move(data);
+ mime_data_[ui::kMimeTypeMozillaURL] = std::move(data);
- if (!base::ContainsKey(mime_data_, ui::Clipboard::kMimeTypeText))
- mime_data_[ui::Clipboard::kMimeTypeText] = FromString(url.spec());
+ if (!base::ContainsKey(mime_data_, ui::kMimeTypeText))
+ mime_data_[ui::kMimeTypeText] = FromString(url.spec());
}
void OSExchangeDataProviderMus::SetFilename(const base::FilePath& path) {
@@ -120,11 +121,11 @@ void OSExchangeDataProviderMus::SetFilenames(
}
std::string joined_data = base::JoinString(paths, "\n");
- mime_data_[ui::Clipboard::kMimeTypeURIList] = FromString(joined_data);
+ mime_data_[ui::kMimeTypeURIList] = FromString(joined_data);
}
void OSExchangeDataProviderMus::SetPickledData(
- const ui::Clipboard::FormatType& format,
+ const ui::ClipboardFormatType& format,
const base::Pickle& pickle) {
const unsigned char* bytes =
reinterpret_cast<const unsigned char*>(pickle.data());
@@ -134,7 +135,7 @@ void OSExchangeDataProviderMus::SetPickledData(
}
bool OSExchangeDataProviderMus::GetString(base::string16* data) const {
- auto it = mime_data_.find(ui::Clipboard::kMimeTypeText);
+ auto it = mime_data_.find(ui::kMimeTypeText);
if (it != mime_data_.end())
*data = base::UTF8ToUTF16(ToString(it->second));
return it != mime_data_.end();
@@ -144,7 +145,7 @@ bool OSExchangeDataProviderMus::GetURLAndTitle(
ui::OSExchangeData::FilenameToURLPolicy policy,
GURL* url,
base::string16* title) const {
- auto it = mime_data_.find(ui::Clipboard::kMimeTypeMozillaURL);
+ auto it = mime_data_.find(ui::kMimeTypeMozillaURL);
if (it == mime_data_.end()) {
title->clear();
return GetPlainTextURL(url) ||
@@ -177,7 +178,7 @@ bool OSExchangeDataProviderMus::GetFilename(base::FilePath* path) const {
bool OSExchangeDataProviderMus::GetFilenames(
std::vector<ui::FileInfo>* file_names) const {
- auto it = mime_data_.find(ui::Clipboard::kMimeTypeURIList);
+ auto it = mime_data_.find(ui::kMimeTypeURIList);
if (it == mime_data_.end())
return false;
@@ -193,7 +194,7 @@ bool OSExchangeDataProviderMus::GetFilenames(
}
bool OSExchangeDataProviderMus::GetPickledData(
- const ui::Clipboard::FormatType& format,
+ const ui::ClipboardFormatType& format,
base::Pickle* data) const {
auto it = mime_data_.find(format.Serialize());
if (it == mime_data_.end())
@@ -207,15 +208,15 @@ bool OSExchangeDataProviderMus::GetPickledData(
}
bool OSExchangeDataProviderMus::HasString() const {
- return base::ContainsKey(mime_data_, ui::Clipboard::kMimeTypeText);
+ return base::ContainsKey(mime_data_, ui::kMimeTypeText);
}
bool OSExchangeDataProviderMus::HasURL(
ui::OSExchangeData::FilenameToURLPolicy policy) const {
- if (base::ContainsKey(mime_data_, ui::Clipboard::kMimeTypeMozillaURL))
+ if (base::ContainsKey(mime_data_, ui::kMimeTypeMozillaURL))
return true;
- auto it = mime_data_.find(ui::Clipboard::kMimeTypeURIList);
+ auto it = mime_data_.find(ui::kMimeTypeURIList);
if (it == mime_data_.end())
return false;
@@ -230,7 +231,7 @@ bool OSExchangeDataProviderMus::HasURL(
}
bool OSExchangeDataProviderMus::HasFile() const {
- auto it = mime_data_.find(ui::Clipboard::kMimeTypeURIList);
+ auto it = mime_data_.find(ui::kMimeTypeURIList);
if (it == mime_data_.end())
return false;
@@ -245,7 +246,7 @@ bool OSExchangeDataProviderMus::HasFile() const {
}
bool OSExchangeDataProviderMus::HasCustomFormat(
- const ui::Clipboard::FormatType& format) const {
+ const ui::ClipboardFormatType& format) const {
return base::ContainsKey(mime_data_, format.Serialize());
}
@@ -281,12 +282,12 @@ void OSExchangeDataProviderMus::SetHtml(const base::string16& html,
bytes.push_back(0xFF);
bytes.push_back(0xFE);
AddString16ToVector(html, &bytes);
- mime_data_[ui::Clipboard::kMimeTypeHTML] = bytes;
+ mime_data_[ui::kMimeTypeHTML] = bytes;
}
bool OSExchangeDataProviderMus::GetHtml(base::string16* html,
GURL* base_url) const {
- auto it = mime_data_.find(ui::Clipboard::kMimeTypeHTML);
+ auto it = mime_data_.find(ui::kMimeTypeHTML);
if (it == mime_data_.end())
return false;
@@ -313,7 +314,7 @@ bool OSExchangeDataProviderMus::GetHtml(base::string16* html,
}
bool OSExchangeDataProviderMus::HasHtml() const {
- return base::ContainsKey(mime_data_, ui::Clipboard::kMimeTypeHTML);
+ return base::ContainsKey(mime_data_, ui::kMimeTypeHTML);
}
#endif
diff --git a/chromium/ui/aura/mus/os_exchange_data_provider_mus.h b/chromium/ui/aura/mus/os_exchange_data_provider_mus.h
index 27a541950dd..ce1b44a0d70 100644
--- a/chromium/ui/aura/mus/os_exchange_data_provider_mus.h
+++ b/chromium/ui/aura/mus/os_exchange_data_provider_mus.h
@@ -46,7 +46,7 @@ class AURA_EXPORT OSExchangeDataProviderMus
void SetURL(const GURL& url, const base::string16& title) override;
void SetFilename(const base::FilePath& path) override;
void SetFilenames(const std::vector<ui::FileInfo>& file_names) override;
- void SetPickledData(const ui::Clipboard::FormatType& format,
+ void SetPickledData(const ui::ClipboardFormatType& format,
const base::Pickle& data) override;
bool GetString(base::string16* data) const override;
@@ -55,13 +55,13 @@ class AURA_EXPORT OSExchangeDataProviderMus
base::string16* title) const override;
bool GetFilename(base::FilePath* path) const override;
bool GetFilenames(std::vector<ui::FileInfo>* file_names) const override;
- bool GetPickledData(const ui::Clipboard::FormatType& format,
+ bool GetPickledData(const ui::ClipboardFormatType& format,
base::Pickle* data) const override;
bool HasString() const override;
bool HasURL(ui::OSExchangeData::FilenameToURLPolicy policy) const override;
bool HasFile() const override;
- bool HasCustomFormat(const ui::Clipboard::FormatType& format) const override;
+ bool HasCustomFormat(const ui::ClipboardFormatType& format) const override;
// Provider doesn't have a consistent interface between operating systems;
// this wasn't seen as a problem when there was a single Provider subclass
diff --git a/chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc b/chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
index 225a515a754..4eea746aefc 100644
--- a/chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
+++ b/chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
@@ -14,12 +14,12 @@
#include "net/base/filename_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
#include "ui/events/platform/platform_event_source.h"
#include "url/gurl.h"
-using ui::Clipboard;
using ui::OSExchangeData;
namespace aura {
@@ -171,8 +171,8 @@ TEST_F(OSExchangeDataProviderMusTest, TestFileToURLConversion) {
}
TEST_F(OSExchangeDataProviderMusTest, TestPickledData) {
- const Clipboard::FormatType kTestFormat =
- Clipboard::GetFormatType("application/vnd.chromium.test");
+ const ui::ClipboardFormatType kTestFormat =
+ ui::ClipboardFormatType::GetType("application/vnd.chromium.test");
base::Pickle saved_pickle;
saved_pickle.WriteInt(1);
diff --git a/chromium/ui/aura/mus/property_converter.cc b/chromium/ui/aura/mus/property_converter.cc
index 86b43b087af..0f1422424fe 100644
--- a/chromium/ui/aura/mus/property_converter.cc
+++ b/chromium/ui/aura/mus/property_converter.cc
@@ -91,12 +91,16 @@ PropertyConverter::PropertyConverter() {
ws::mojom::WindowManager::kRestoreBounds_Property);
RegisterSizeProperty(client::kPreferredSize,
ws::mojom::WindowManager::kPreferredSize_Property);
+ RegisterSizeProperty(client::kMaximumSize,
+ ws::mojom::WindowManager::kMaximumSize_Property);
RegisterSizeProperty(client::kMinimumSize,
ws::mojom::WindowManager::kMinimumSize_Property);
RegisterStringProperty(client::kNameKey,
ws::mojom::WindowManager::kName_Property);
RegisterString16Property(client::kTitleKey,
ws::mojom::WindowManager::kWindowTitle_Property);
+ RegisterSizeFProperty(client::kAspectRatio,
+ ws::mojom::WindowManager::kAspectRatio_Property);
RegisterPrimitiveProperty(
client::kWindowCornerRadiusKey,
ws::mojom::WindowManager::kWindowCornerRadius_Property,
@@ -138,6 +142,11 @@ const void* PropertyConverter::GetPropertyKeyFromTransportName(
return size_property.first->name;
}
+ for (const auto& size_f_property : size_f_properties_) {
+ if (size_f_property.second == transport_name)
+ return size_f_property.first->name;
+ }
+
for (const auto& string_property : string_properties_) {
if (string_property.second == transport_name)
return string_property.first->name;
@@ -201,6 +210,12 @@ bool PropertyConverter::ConvertPropertyForTransport(
return true;
}
+ auto* size_f_key = static_cast<const WindowProperty<gfx::SizeF*>*>(key);
+ if (size_f_properties_.count(size_f_key) > 0) {
+ *transport_value = GetArray(window, size_f_key);
+ return true;
+ }
+
auto* string_key = static_cast<const WindowProperty<std::string*>*>(key);
if (string_properties_.count(string_key) > 0) {
*transport_value = GetArray(window, string_key);
@@ -254,6 +269,10 @@ std::string PropertyConverter::GetTransportNameForPropertyKey(const void* key) {
if (size_properties_.count(size_key) > 0)
return size_properties_[size_key];
+ auto* size_f_key = static_cast<const WindowProperty<gfx::SizeF*>*>(key);
+ if (size_f_properties_.count(size_f_key) > 0)
+ return size_f_properties_[size_f_key];
+
auto* string_key = static_cast<const WindowProperty<std::string*>*>(key);
if (string_properties_.count(string_key) > 0)
return string_properties_[string_key];
@@ -335,6 +354,18 @@ void PropertyConverter::SetPropertyFromTransportValue(
}
}
+ for (const auto& size_f_property : size_f_properties_) {
+ if (size_f_property.second == transport_name) {
+ if (data->size() != 8u) {
+ DVLOG(2) << "Property size mismatch (gfx::Size): " << transport_name;
+ return;
+ }
+ const gfx::SizeF value = mojo::ConvertTo<gfx::SizeF>(*data);
+ window->SetProperty(size_f_property.first, new gfx::SizeF(value));
+ return;
+ }
+ }
+
for (const auto& string_property : string_properties_) {
if (string_property.second == transport_name) {
// TODO(msw): Validate the data somehow, before trying to convert?
@@ -436,6 +467,15 @@ void PropertyConverter::RegisterSizeProperty(
transport_names_.insert(transport_name);
}
+void PropertyConverter::RegisterSizeFProperty(
+ const WindowProperty<gfx::SizeF*>* property,
+ const char* transport_name) {
+ DCHECK(!IsTransportNameRegistered(transport_name))
+ << "Property already registered: " << transport_name;
+ size_f_properties_[property] = transport_name;
+ transport_names_.insert(transport_name);
+}
+
void PropertyConverter::RegisterStringProperty(
const WindowProperty<std::string*>* property,
const char* transport_name) {
diff --git a/chromium/ui/aura/mus/property_converter.h b/chromium/ui/aura/mus/property_converter.h
index 82650db1321..099feeafb9e 100644
--- a/chromium/ui/aura/mus/property_converter.h
+++ b/chromium/ui/aura/mus/property_converter.h
@@ -112,6 +112,8 @@ class AURA_EXPORT PropertyConverter {
const char* transport_name);
void RegisterSizeProperty(const WindowProperty<gfx::Size*>* property,
const char* transport_name);
+ void RegisterSizeFProperty(const WindowProperty<gfx::SizeF*>* property,
+ const char* transport_name);
void RegisterStringProperty(const WindowProperty<std::string*>* property,
const char* transport_name);
void RegisterString16Property(const WindowProperty<base::string16*>* property,
@@ -165,6 +167,7 @@ class AURA_EXPORT PropertyConverter {
image_properties_;
std::map<const WindowProperty<gfx::Rect*>*, const char*> rect_properties_;
std::map<const WindowProperty<gfx::Size*>*, const char*> size_properties_;
+ std::map<const WindowProperty<gfx::SizeF*>*, const char*> size_f_properties_;
std::map<const WindowProperty<std::string*>*, const char*> string_properties_;
std::map<const WindowProperty<base::string16*>*, const char*>
string16_properties_;
diff --git a/chromium/ui/aura/mus/property_utils.cc b/chromium/ui/aura/mus/property_utils.cc
index d261320a22c..7f00f7fa06f 100644
--- a/chromium/ui/aura/mus/property_utils.cc
+++ b/chromium/ui/aura/mus/property_utils.cc
@@ -18,8 +18,6 @@ client::WindowType UiWindowTypeToWindowType(ws::mojom::WindowType type) {
switch (type) {
case ws::mojom::WindowType::WINDOW:
return client::WINDOW_TYPE_NORMAL;
- case ws::mojom::WindowType::PANEL:
- return client::WINDOW_TYPE_PANEL;
case ws::mojom::WindowType::CONTROL:
return client::WINDOW_TYPE_CONTROL;
case ws::mojom::WindowType::WINDOW_FRAMELESS:
diff --git a/chromium/ui/aura/mus/text_input_client_impl.cc b/chromium/ui/aura/mus/text_input_client_impl.cc
index 3d8a041f2ee..86dd35db082 100644
--- a/chromium/ui/aura/mus/text_input_client_impl.cc
+++ b/chromium/ui/aura/mus/text_input_client_impl.cc
@@ -90,4 +90,8 @@ void TextInputClientImpl::DispatchKeyEventPostIME(
key_event->WillHandleAsync().Run(handled);
}
+void TextInputClientImpl::EnsureCaretNotInRect(const gfx::Rect& rect) {
+ text_input_client_->EnsureCaretNotInRect(rect);
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/mus/text_input_client_impl.h b/chromium/ui/aura/mus/text_input_client_impl.h
index 5d50c815023..12a21a9623a 100644
--- a/chromium/ui/aura/mus/text_input_client_impl.h
+++ b/chromium/ui/aura/mus/text_input_client_impl.h
@@ -36,6 +36,7 @@ class TextInputClientImpl : public ws::mojom::TextInputClient {
void DispatchKeyEventPostIME(
std::unique_ptr<ui::Event> event,
DispatchKeyEventPostIMECallback callback) override;
+ void EnsureCaretNotInRect(const gfx::Rect& rect) override;
ui::TextInputClient* text_input_client_;
mojo::Binding<ws::mojom::TextInputClient> binding_;
diff --git a/chromium/ui/aura/mus/window_mus.h b/chromium/ui/aura/mus/window_mus.h
index 11ca0ae9419..9562f0ff81d 100644
--- a/chromium/ui/aura/mus/window_mus.h
+++ b/chromium/ui/aura/mus/window_mus.h
@@ -11,9 +11,9 @@
#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"
+#include "ui/base/mojo/cursor.mojom.h"
namespace gfx {
class Rect;
@@ -28,7 +28,6 @@ enum class OrderDirection;
namespace viz {
class FrameSinkId;
-class LocalSurfaceId;
}
namespace aura {
@@ -82,19 +81,15 @@ class AURA_EXPORT WindowMus {
virtual void ReorderFromServer(WindowMus* child,
WindowMus* relative,
ws::mojom::OrderDirection) = 0;
- virtual void SetBoundsFromServer(
- const gfx::Rect& bounds,
- const base::Optional<viz::LocalSurfaceId>& local_surface_id) = 0;
+ virtual void SetBoundsFromServer(const gfx::Rect& bounds) = 0;
virtual void SetTransformFromServer(const gfx::Transform& transform) = 0;
virtual void SetVisibleFromServer(bool visible) = 0;
virtual void SetOpacityFromServer(float opacity) = 0;
- virtual void SetCursorFromServer(const ui::CursorData& cursor) = 0;
+ virtual void SetCursorFromServer(const ui::Cursor& cursor) = 0;
virtual void SetPropertyFromServer(const std::string& property_name,
const std::vector<uint8_t>* data) = 0;
virtual void SetFrameSinkIdFromServer(
const viz::FrameSinkId& frame_sink_id) = 0;
- virtual const viz::LocalSurfaceId& GetOrAllocateLocalSurfaceId(
- const gfx::Size& new_size) = 0;
// The window was deleted on the server side. DestroyFromServer() should
// result in deleting |this|.
virtual void DestroyFromServer() = 0;
@@ -110,6 +105,9 @@ class AURA_EXPORT WindowMus {
virtual const viz::LocalSurfaceIdAllocation&
GetLocalSurfaceIdAllocation() = 0;
+ // Returns true if the window has a LocalSurfaceId.
+ virtual bool HasLocalSurfaceId() = 0;
+
// Called in the rare case when WindowTreeClient needs to change state and
// can't go through one of the SetFooFromServer() functions above. Generally
// because it needs to call another function that as a side effect changes the
@@ -127,8 +125,6 @@ class AURA_EXPORT WindowMus {
virtual void NotifyEmbeddedAppDisconnected() = 0;
- virtual bool HasLocalLayerTreeFrameSink() = 0;
-
virtual float GetDeviceScaleFactor() = 0;
private:
diff --git a/chromium/ui/aura/mus/window_port_mus.cc b/chromium/ui/aura/mus/window_port_mus.cc
index e970a5d30dc..88fd879d6e8 100644
--- a/chromium/ui/aura/mus/window_port_mus.cc
+++ b/chromium/ui/aura/mus/window_port_mus.cc
@@ -9,17 +9,20 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/no_destructor.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/common/surfaces/parent_local_surface_id_allocator.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"
+#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/transient_window_client.h"
#include "ui/aura/env.h"
-#include "ui/aura/mus/client_surface_embedder.h"
+#include "ui/aura/mus/mus_lsi_allocator.h"
#include "ui/aura/mus/property_converter.h"
#include "ui/aura/mus/property_utils.h"
#include "ui/aura/mus/window_tree_client.h"
@@ -96,7 +99,7 @@ WindowPortMus::WindowPortMus(WindowTreeClient* client,
weak_ptr_factory_(this) {}
WindowPortMus::~WindowPortMus() {
- client_surface_embedder_.reset();
+ allocator_.reset();
// DESTROY is only scheduled from DestroyFromServer(), meaning if DESTROY is
// present then the server originated the change.
@@ -124,7 +127,7 @@ void WindowPortMus::SetImeVisibility(bool visible,
window_tree_client_->SetImeVisibility(this, visible, std::move(state));
}
-void WindowPortMus::SetCursor(const ui::CursorData& cursor) {
+void WindowPortMus::SetCursor(const ui::Cursor& cursor) {
if (cursor_.IsSameAs(cursor))
return;
@@ -202,8 +205,6 @@ WindowPortMus::RequestLayerTreeFrameSink(
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;
params.client_name = kMus;
@@ -224,6 +225,22 @@ viz::FrameSinkId WindowPortMus::GenerateFrameSinkIdFromServerId() const {
return viz::FrameSinkId(kClientSelfId, server_id());
}
+gfx::Size WindowPortMus::GetSizeInPixels() {
+ return GetSizeInPixels(window_->bounds().size());
+}
+
+gfx::Size WindowPortMus::GetSizeInPixels(const gfx::Size& size) {
+ return gfx::ScaleToCeiledSize(size, GetDeviceScaleFactor());
+}
+
+void WindowPortMus::SetAllocator(std::unique_ptr<MusLsiAllocator> allocator) {
+ allocator_ = std::move(allocator);
+ // This triggers allocating a LocalSurfaceId *and* notifying the server.
+ // TODO: investigate making allocation match that of WindowPortLocal, this may
+ // be called earlier than WindowPortLocal allocates the id.
+ allocator_->AllocateLocalSurfaceId();
+}
+
WindowPortMus::ServerChangeIdType WindowPortMus::ScheduleChange(
const ServerChangeType type,
const ServerChangeData& data) {
@@ -319,6 +336,9 @@ bool WindowPortMus::PrepareForEmbed() {
return false;
has_embedding_ = true;
+ DCHECK(!allocator_.get());
+ SetAllocator(MusLsiAllocator::CreateAllocator(MusLsiAllocatorType::kEmbed,
+ this, window_tree_client_));
return true;
}
@@ -327,8 +347,10 @@ void WindowPortMus::OnEmbedAck(
base::WeakPtr<WindowPortMus> window,
ws::mojom::WindowTree::EmbedCallback real_callback,
bool result) {
- if (window && !result)
+ if (window && !result) {
window->has_embedding_ = false;
+ window->allocator_.reset();
+ }
std::move(real_callback).Run(window && result);
}
@@ -370,18 +392,15 @@ void WindowPortMus::ReorderFromServer(WindowMus* child,
window_->StackChildAbove(child->GetWindow(), relative->GetWindow());
}
-void WindowPortMus::SetBoundsFromServer(
- const gfx::Rect& bounds,
- const base::Optional<viz::LocalSurfaceId>& local_surface_id) {
+void WindowPortMus::SetBoundsFromServer(const gfx::Rect& bounds) {
+ // Changes to TOP_LEVEL and EMBED are routed through WindowTreeHostMus.
+ DCHECK(window_mus_type() != WindowMusType::TOP_LEVEL &&
+ window_mus_type() != WindowMusType::EMBED);
ServerChangeData data;
data.bounds_in_dip = bounds;
ScopedServerChange change(this, ServerChangeType::BOUNDS, data);
- last_surface_size_in_pixels_ =
- gfx::ConvertSizeToPixel(GetDeviceScaleFactor(), bounds.size());
- if (local_surface_id)
- parent_local_surface_id_allocator_.Reset(*local_surface_id);
- else
- parent_local_surface_id_allocator_.Invalidate();
+ // XXX this seems like the wrong place to cache size.
+ last_surface_size_in_pixels_ = GetSizeInPixels(bounds.size());
window_->SetBounds(bounds);
}
@@ -406,7 +425,7 @@ void WindowPortMus::SetOpacityFromServer(float opacity) {
window_->layer()->SetOpacity(opacity);
}
-void WindowPortMus::SetCursorFromServer(const ui::CursorData& cursor) {
+void WindowPortMus::SetCursorFromServer(const ui::Cursor& cursor) {
// As this does nothing more than set the cursor we don't need to use
// ServerChange.
cursor_ = cursor;
@@ -424,37 +443,11 @@ void WindowPortMus::SetPropertyFromServer(
void WindowPortMus::SetFrameSinkIdFromServer(
const viz::FrameSinkId& frame_sink_id) {
+ // Only called if this window is embedding another window.
+ DCHECK(has_embedding_);
embed_frame_sink_id_ = frame_sink_id;
window_->SetEmbedFrameSinkId(embed_frame_sink_id_);
- // We may not have allocated a LocalSurfaceId. Call OnWindowMusBoundsChanged()
- // to trigger updating the LocalSurfaceId *and* notifying the server.
- window_tree_client_->OnWindowMusBoundsChanged(this, window_->bounds(),
- window_->bounds());
-}
-
-const viz::LocalSurfaceId& WindowPortMus::GetOrAllocateLocalSurfaceId(
- const gfx::Size& surface_size_in_pixels) {
- if (last_surface_size_in_pixels_ != surface_size_in_pixels ||
- !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
- // deadline hits.
- if (window_->IsEmbeddingClient())
- UpdatePrimarySurfaceId();
-
- if (local_layer_tree_frame_sink_)
- local_layer_tree_frame_sink_->SetLocalSurfaceId(current_local_surface_id);
-
- return current_local_surface_id;
+ allocator_->OnFrameSinkIdChanged();
}
void WindowPortMus::DestroyFromServer() {
@@ -513,41 +506,52 @@ WindowPortMus::ChangeSource WindowPortMus::OnTransientChildRemoved(
}
void WindowPortMus::AllocateLocalSurfaceId() {
- parent_local_surface_id_allocator_.GenerateId();
- UpdatePrimarySurfaceId();
- if (local_layer_tree_frame_sink_) {
- local_layer_tree_frame_sink_->SetLocalSurfaceId(
- GetLocalSurfaceIdAllocation().local_surface_id());
+ // This API does not make sense for EMBED.
+ DCHECK_NE(window_mus_type(), WindowMusType::EMBED);
+ if (!allocator_ && window_mus_type() == WindowMusType::LOCAL) {
+ SetAllocator(MusLsiAllocator::CreateAllocator(MusLsiAllocatorType::kLocal,
+ this, window_tree_client_));
+ } else if (allocator_) {
+ allocator_->AllocateLocalSurfaceId();
}
}
viz::ScopedSurfaceIdAllocator WindowPortMus::GetSurfaceIdAllocator(
base::OnceCallback<void()> allocation_task) {
- return viz::ScopedSurfaceIdAllocator(&parent_local_surface_id_allocator_,
- std::move(allocation_task));
+ // This API does not make sense for EMBED.
+ DCHECK_NE(window_mus_type(), WindowMusType::EMBED);
+ return allocator_
+ ? allocator_->GetSurfaceIdAllocator(std::move(allocation_task))
+ : viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
}
void WindowPortMus::InvalidateLocalSurfaceId() {
- parent_local_surface_id_allocator_.Invalidate();
+ // This API does not make sense for EMBED.
+ DCHECK_NE(window_mus_type(), WindowMusType::EMBED);
+ if (allocator_)
+ allocator_->InvalidateLocalSurfaceId();
}
void WindowPortMus::UpdateLocalSurfaceIdFromEmbeddedClient(
const viz::LocalSurfaceIdAllocation&
embedded_client_local_surface_id_allocation) {
- parent_local_surface_id_allocator_.UpdateFromChild(
- embedded_client_local_surface_id_allocation);
- UpdatePrimarySurfaceId();
-
- // OnWindowMusBoundsChanged() triggers notifying the server of the new
- // LocalSurfaceId.
- window_tree_client_->OnWindowMusBoundsChanged(this, window_->bounds(),
- window_->bounds());
+ // This API does not make sense for EMBED.
+ DCHECK_NE(window_mus_type(), WindowMusType::EMBED);
+ if (allocator_) {
+ allocator_->UpdateLocalSurfaceIdFromEmbeddedClient(
+ embedded_client_local_surface_id_allocation);
+ }
}
const viz::LocalSurfaceIdAllocation&
WindowPortMus::GetLocalSurfaceIdAllocation() {
- return parent_local_surface_id_allocator_
- .GetCurrentLocalSurfaceIdAllocation();
+ static base::NoDestructor<viz::LocalSurfaceIdAllocation> empty_allocation;
+ return allocator_ ? allocator_->GetLocalSurfaceIdAllocation()
+ : *empty_allocation;
+}
+
+bool WindowPortMus::HasLocalSurfaceId() {
+ return allocator_.get() != nullptr;
}
std::unique_ptr<WindowMusChangeData>
@@ -578,14 +582,11 @@ void WindowPortMus::PrepareForDestroy() {
void WindowPortMus::NotifyEmbeddedAppDisconnected() {
has_embedding_ = false;
+ allocator_ = nullptr;
for (WindowObserver& observer : *GetObservers(window_))
observer.OnEmbeddedAppDisconnected(window_);
}
-bool WindowPortMus::HasLocalLayerTreeFrameSink() {
- return !!local_layer_tree_frame_sink_;
-}
-
float WindowPortMus::GetDeviceScaleFactor() {
return window_->layer()->device_scale_factor();
}
@@ -597,13 +598,8 @@ void WindowPortMus::OnPreInit(Window* window) {
void WindowPortMus::OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) {
- if (!window_->IsRootWindow() && GetLocalSurfaceIdAllocation().IsValid() &&
- local_layer_tree_frame_sink_) {
- parent_local_surface_id_allocator_.GenerateId();
- local_layer_tree_frame_sink_->SetLocalSurfaceId(
- parent_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
- .local_surface_id());
- }
+ if (allocator_)
+ allocator_->OnDeviceScaleFactorChanged();
if (window_->delegate()) {
window_->delegate()->OnDeviceScaleFactorChanged(old_device_scale_factor,
@@ -645,10 +641,12 @@ void WindowPortMus::OnDidChangeBounds(const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
ServerChangeData change_data;
change_data.bounds_in_dip = new_bounds;
- if (!RemoveChangeByTypeAndData(ServerChangeType::BOUNDS, change_data))
+ const bool from_server =
+ RemoveChangeByTypeAndData(ServerChangeType::BOUNDS, change_data);
+ if (allocator_)
+ allocator_->OnDidChangeBounds(GetSizeInPixels(), from_server);
+ if (!from_server)
window_tree_client_->OnWindowMusBoundsChanged(this, old_bounds, new_bounds);
- if (client_surface_embedder_)
- client_surface_embedder_->UpdateSizeAndGutters();
}
void WindowPortMus::OnDidChangeTransform(const gfx::Transform& old_transform,
@@ -680,6 +678,11 @@ void WindowPortMus::OnPropertyChanged(const void* key,
if (!window_)
return;
+ if (key == client::kDragDropDelegateKey) {
+ SetCanAcceptDrops(window_->GetProperty(client::kDragDropDelegateKey) !=
+ nullptr);
+ }
+
ServerChangeData change_data;
change_data.property_name =
GetPropertyConverter()->GetTransportNameForPropertyKey(key);
@@ -693,23 +696,9 @@ void WindowPortMus::OnPropertyChanged(const void* key,
std::unique_ptr<cc::LayerTreeFrameSink>
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, 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_);
-
- gfx::Size size_in_pixel =
- gfx::ConvertSizeToPixel(GetDeviceScaleFactor(), window_->bounds().size());
- // Make sure |local_surface_id_| and |last_surface_size_in_pixels_| are
- // correct for the new created |local_layer_tree_frame_sink_|.
- GetOrAllocateLocalSurfaceId(size_in_pixel);
- return client_layer_tree_frame_sink;
+ // This function should not be called for WindowPortMus.
+ NOTIMPLEMENTED();
+ return nullptr;
}
void WindowPortMus::OnEventTargetingPolicyChanged() {
@@ -725,6 +714,14 @@ void WindowPortMus::RegisterFrameSinkId(const viz::FrameSinkId& frame_sink_id) {
return;
window_tree_client_->RegisterFrameSinkId(this, frame_sink_id);
+ // This api only makes sense for local windows.
+ DCHECK_EQ(window_mus_type(), WindowMusType::LOCAL);
+ if (allocator_) {
+ DCHECK_EQ(MusLsiAllocatorType::kLocal, allocator_->type());
+ } else {
+ SetAllocator(MusLsiAllocator::CreateAllocator(MusLsiAllocatorType::kLocal,
+ this, window_tree_client_));
+ }
}
void WindowPortMus::UnregisterFrameSinkId(
@@ -744,26 +741,6 @@ void WindowPortMus::TrackOcclusionState() {
window_tree_client_->TrackOcclusionState(this);
}
-void WindowPortMus::UpdatePrimarySurfaceId() {
- if (window_mus_type() != WindowMusType::LOCAL)
- return;
-
- if (!window_->IsEmbeddingClient() || !GetLocalSurfaceIdAllocation().IsValid())
- return;
-
- primary_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_->SetSurfaceId(primary_surface_id_);
- client_surface_embedder_->UpdateSizeAndGutters();
-}
-
void WindowPortMus::SetOcclusionStateFromServer(
ws::mojom::OcclusionState occlusion_state) {
const Window::OcclusionState new_state =
diff --git a/chromium/ui/aura/mus/window_port_mus.h b/chromium/ui/aura/mus/window_port_mus.h
index 14f60e525f5..adf78045962 100644
--- a/chromium/ui/aura/mus/window_port_mus.h
+++ b/chromium/ui/aura/mus/window_port_mus.h
@@ -15,9 +15,7 @@
#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"
#include "services/ws/public/mojom/window_tree.mojom.h"
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/aura_export.h"
@@ -25,6 +23,7 @@
#include "ui/aura/mus/window_mus.h"
#include "ui/aura/window.h"
#include "ui/aura/window_port.h"
+#include "ui/base/mojo/cursor.mojom.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/platform_window/mojo/text_input_state.mojom.h"
@@ -45,7 +44,7 @@ class RasterContextProvider;
namespace aura {
-class ClientSurfaceEmbedder;
+class MusLsiAllocator;
class PropertyConverter;
class WindowTreeClient;
class WindowTreeClientTestApi;
@@ -67,10 +66,6 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
Window* window() { return window_; }
const Window* window() const { return window_; }
- ClientSurfaceEmbedder* client_surface_embedder() const {
- return client_surface_embedder_.get();
- }
-
const viz::SurfaceId& PrimarySurfaceIdForTesting() const {
return primary_surface_id_;
}
@@ -78,8 +73,8 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
void SetTextInputState(ui::mojom::TextInputStatePtr state);
void SetImeVisibility(bool visible, ui::mojom::TextInputStatePtr state);
- const ui::CursorData& cursor() const { return cursor_; }
- void SetCursor(const ui::CursorData& cursor);
+ const ui::Cursor& cursor() const { return cursor_; }
+ void SetCursor(const ui::Cursor& cursor);
// Sets the EventTargetingPolicy, default is TARGET_AND_DESCENDANTS.
void SetEventTargetingPolicy(ws::mojom::EventTargetingPolicy policy);
@@ -107,6 +102,9 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
viz::FrameSinkId GenerateFrameSinkIdFromServerId() const;
+ gfx::Size GetSizeInPixels();
+ gfx::Size GetSizeInPixels(const gfx::Size& size);
+
private:
friend class WindowPortMusTestHelper;
friend class WindowTreeClient;
@@ -212,6 +210,8 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
// and needs to consider ancestors' visibility as well.
class VisibilityTracker;
+ void SetAllocator(std::unique_ptr<MusLsiAllocator> allocator);
+
// Creates and adds a ServerChange to |server_changes_|. Returns the id
// assigned to the ServerChange.
ServerChangeIdType ScheduleChange(const ServerChangeType type,
@@ -220,7 +220,7 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
// Removes a ServerChange by id.
void RemoveChangeById(ServerChangeIdType change_id);
- // If there is a schedule change matching |type| and |data| it is removed and
+ // If there is a scheduled change matching |type| and |data| it is removed and
// true is returned. If no matching change is scheduled returns false.
bool RemoveChangeByTypeAndData(const ServerChangeType type,
const ServerChangeData& data);
@@ -247,19 +247,15 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
void ReorderFromServer(WindowMus* child,
WindowMus* relative,
ws::mojom::OrderDirection) override;
- void SetBoundsFromServer(
- const gfx::Rect& bounds,
- const base::Optional<viz::LocalSurfaceId>& local_surface_id) override;
+ void SetBoundsFromServer(const gfx::Rect& bounds) override;
void SetTransformFromServer(const gfx::Transform& transform) override;
void SetVisibleFromServer(bool visible) override;
void SetOpacityFromServer(float opacity) override;
- void SetCursorFromServer(const ui::CursorData& cursor) override;
+ void SetCursorFromServer(const ui::Cursor& cursor) override;
void SetPropertyFromServer(
const std::string& property_name,
const std::vector<uint8_t>* property_data) override;
void SetFrameSinkIdFromServer(const viz::FrameSinkId& frame_sink_id) override;
- const viz::LocalSurfaceId& GetOrAllocateLocalSurfaceId(
- const gfx::Size& surface_size_in_pixels) override;
void UpdateLocalSurfaceIdFromEmbeddedClient(
const viz::LocalSurfaceIdAllocation&
embedded_client_local_surface_id_allocation) override;
@@ -268,13 +264,13 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
void RemoveTransientChildFromServer(WindowMus* child) override;
ChangeSource OnTransientChildAdded(WindowMus* child) override;
ChangeSource OnTransientChildRemoved(WindowMus* child) override;
+ bool HasLocalSurfaceId() override;
std::unique_ptr<WindowMusChangeData> PrepareForServerBoundsChange(
const gfx::Rect& bounds) override;
std::unique_ptr<WindowMusChangeData> PrepareForServerVisibilityChange(
bool value) override;
void PrepareForDestroy() override;
void NotifyEmbeddedAppDisconnected() override;
- bool HasLocalLayerTreeFrameSink() override;
float GetDeviceScaleFactor() override;
// WindowPort:
@@ -306,8 +302,6 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
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);
@@ -323,21 +317,19 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
Window* window_ = nullptr;
- // Used when this window is embedding a client.
- std::unique_ptr<ClientSurfaceEmbedder> client_surface_embedder_;
-
ServerChangeIdType next_server_change_id_ = 0;
ServerChanges server_changes_;
viz::SurfaceId primary_surface_id_;
- // TODO(sad, fsamuel): For 'mash' mode, where the embedder is responsible for
- // allocating the LocalSurfaceIds, this should use a
- // ChildLocalSurfaceIdAllocator instead.
- viz::ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_;
- gfx::Size last_surface_size_in_pixels_;
+ // Manages allocation of LocalSurfaceIds. Only created if this window needs
+ // allocated LocalSurfaceIds.
+ std::unique_ptr<MusLsiAllocator> allocator_;
+
+ // This is set the first time an id is generated.
+ base::Optional<gfx::Size> last_surface_size_in_pixels_;
- ui::CursorData cursor_;
+ ui::Cursor cursor_;
// Set if this class calls SetEmbedFrameSinkId() on the associated window.
viz::FrameSinkId embed_frame_sink_id_;
diff --git a/chromium/ui/aura/mus/window_port_mus_unittest.cc b/chromium/ui/aura/mus/window_port_mus_unittest.cc
index 161ec145b66..649a715d459 100644
--- a/chromium/ui/aura/mus/window_port_mus_unittest.cc
+++ b/chromium/ui/aura/mus/window_port_mus_unittest.cc
@@ -7,7 +7,9 @@
#include "base/optional.h"
#include "base/run_loop.h"
#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
+#include "components/viz/common/surfaces/child_local_surface_id_allocator.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/drag_drop_delegate.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"
@@ -90,16 +92,18 @@ TEST_F(WindowPortMusTest, ClientSurfaceEmbedderUpdatesLayer) {
Window window(nullptr);
window.Init(ui::LAYER_NOT_DRAWN);
window.SetBounds(gfx::Rect(300, 300));
- window.SetEmbedFrameSinkId(viz::FrameSinkId(0, 1));
+ WindowPortMusTestHelper(&window).SimulateEmbedding();
// Allocate a new LocalSurfaceId. The ui::Layer should be updated.
window.AllocateLocalSurfaceId();
- auto* window_mus = WindowPortMus::Get(&window);
viz::LocalSurfaceId local_surface_id =
window.GetLocalSurfaceIdAllocation().local_surface_id();
+ ClientSurfaceEmbedder* client_surface_embedder =
+ WindowPortMusTestHelper(&window).GetClientSurfaceEmbedder();
+ ASSERT_TRUE(client_surface_embedder);
viz::SurfaceId primary_surface_id =
- window_mus->client_surface_embedder()->GetSurfaceIdForTesting();
+ client_surface_embedder->GetSurfaceIdForTesting();
EXPECT_EQ(local_surface_id, primary_surface_id.local_surface_id());
}
@@ -110,7 +114,7 @@ TEST_F(WindowPortMusTest,
window.set_owned_by_parent(false);
window.SetBounds(gfx::Rect(300, 300));
// Simulate an embedding.
- window.SetEmbedFrameSinkId(viz::FrameSinkId(0, 1));
+ WindowPortMusTestHelper(&window).SimulateEmbedding();
root_window()->AddChild(&window);
// AckAllChanges() so that can verify a bounds change happens from
@@ -132,18 +136,20 @@ TEST_F(WindowPortMusTest,
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()
- ->GetSurfaceIdForTesting()
- .local_surface_id());
+ ClientSurfaceEmbedder* client_surface_embedder =
+ WindowPortMusTestHelper(&window).GetClientSurfaceEmbedder();
+ ASSERT_TRUE(client_surface_embedder);
+ EXPECT_EQ(
+ updated_id,
+ client_surface_embedder->GetSurfaceIdForTesting().local_surface_id());
// The server is notified of a bounds change, so that it sees the new
// LocalSurfaceId.
ASSERT_EQ(1u,
window_tree()->GetChangeCountForType(WindowTreeChangeType::BOUNDS));
ASSERT_TRUE(window_tree()->last_local_surface_id());
+ auto* window_mus = WindowPortMus::Get(&window);
+ ASSERT_TRUE(window_mus);
EXPECT_EQ(window_mus->server_id(), window_tree()->window_id());
EXPECT_EQ(updated_id, *(window_tree()->last_local_surface_id()));
}
@@ -201,4 +207,87 @@ TEST_F(WindowPortMusTest, LocalOcclusionStateFromVisibility) {
EXPECT_EQ(Window::OcclusionState::HIDDEN, window.occlusion_state());
}
+TEST_F(WindowPortMusTest, PrepareForEmbed) {
+ Window window(nullptr);
+ window.Init(ui::LAYER_NOT_DRAWN);
+ window.set_owned_by_parent(false);
+ window.SetBounds(gfx::Rect(400, 300));
+
+ WindowPortMusTestHelper helper(&window);
+ helper.SimulateEmbedding();
+ ClientSurfaceEmbedder* client_surface_embedder =
+ WindowPortMusTestHelper(&window).GetClientSurfaceEmbedder();
+ ASSERT_TRUE(client_surface_embedder);
+ EXPECT_TRUE(client_surface_embedder->HasPrimarySurfaceId());
+}
+
+class TestDragDropDelegate : public client::DragDropDelegate {
+ public:
+ TestDragDropDelegate() = default;
+ ~TestDragDropDelegate() override = default;
+
+ // client::DragDropDelegate:
+ void OnDragEntered(const ui::DropTargetEvent& event) override {}
+ int OnDragUpdated(const ui::DropTargetEvent& event) override { return 0; }
+ void OnDragExited() override {}
+ int OnPerformDrop(const ui::DropTargetEvent& event) override { return 0; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestDragDropDelegate);
+};
+
+TEST_F(WindowPortMusTest, CanAcceptDrops) {
+ TestDragDropDelegate test_delegate;
+
+ Window window(nullptr);
+ window.Init(ui::LAYER_NOT_DRAWN);
+ window.set_owned_by_parent(false);
+ window.SetBounds(gfx::Rect(400, 300));
+
+ EXPECT_EQ(0u, window_tree()->get_and_clear_accepts_drops_count());
+
+ // Setting the DragDropDelegate should implicitly call
+ // SetCanAcceptDrops(true).
+ client::SetDragDropDelegate(&window, &test_delegate);
+ EXPECT_EQ(1u, window_tree()->get_and_clear_accepts_drops_count());
+ EXPECT_TRUE(window_tree()->last_accepts_drops());
+
+ // And removing the DragDropDelegate should implicitly call
+ // SetCanAcceptDrops(false).
+ client::SetDragDropDelegate(&window, nullptr);
+ EXPECT_EQ(1u, window_tree()->get_and_clear_accepts_drops_count());
+ EXPECT_FALSE(window_tree()->last_accepts_drops());
+}
+
+TEST_F(WindowPortMusTest, RegisterFrameSinkId) {
+ 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_tree()->AckAllChanges();
+ window.SetEmbedFrameSinkId(viz::FrameSinkId(0, 1));
+
+ // Setting a FrameSinkId should trigger generating LocalSurfaceIds.
+ ASSERT_EQ(1u,
+ window_tree()->GetChangeCountForType(WindowTreeChangeType::BOUNDS));
+ ASSERT_TRUE(window_tree()->last_local_surface_id());
+ EXPECT_EQ(window_tree()->last_local_surface_id(),
+ window.GetLocalSurfaceIdAllocation().local_surface_id());
+ auto local_surface_id =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
+ window_tree()->AckAllChanges();
+
+ // Changing the bounds should trigger a new LocalSurfaceId.
+ window.SetBounds(gfx::Rect(400, 310));
+ ASSERT_EQ(1u,
+ window_tree()->GetChangeCountForType(WindowTreeChangeType::BOUNDS));
+ ASSERT_TRUE(window_tree()->last_local_surface_id());
+ EXPECT_EQ(window_tree()->last_local_surface_id(),
+ window.GetLocalSurfaceIdAllocation().local_surface_id());
+ EXPECT_NE(local_surface_id,
+ window.GetLocalSurfaceIdAllocation().local_surface_id());
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/mus/window_tree_client.cc b/chromium/ui/aura/mus/window_tree_client.cc
index a0dbdb0bb41..47c1a76c3c4 100644
--- a/chromium/ui/aura/mus/window_tree_client.cc
+++ b/chromium/ui/aura/mus/window_tree_client.cc
@@ -34,6 +34,7 @@
#include "ui/aura/env.h"
#include "ui/aura/env_input_state_controller.h"
#include "ui/aura/mus/capture_synchronizer.h"
+#include "ui/aura/mus/client_side_window_move_handler.h"
#include "ui/aura/mus/drag_drop_controller_mus.h"
#include "ui/aura/mus/embed_root.h"
#include "ui/aura/mus/embed_root_delegate.h"
@@ -234,8 +235,8 @@ void WindowTreeClient::SetCanFocus(Window* window, bool can_focus) {
}
void WindowTreeClient::SetCursor(WindowMus* window,
- const ui::CursorData& old_cursor,
- const ui::CursorData& new_cursor) {
+ const ui::Cursor& old_cursor,
+ const ui::Cursor& new_cursor) {
DCHECK(tree_);
const uint32_t change_id = ScheduleInFlightChange(
@@ -283,11 +284,6 @@ void WindowTreeClient::RegisterFrameSinkId(
WindowMus* window,
const viz::FrameSinkId& frame_sink_id) {
tree_->AttachFrameSinkId(window->server_id(), frame_sink_id);
-
- // Call OnWindowMusBoundsChanged() to force allocation of a LocalSurfaceId as
- // well as notifying the server of the LocalSurfaceId.
- const gfx::Rect bounds = window->GetWindow()->bounds();
- OnWindowMusBoundsChanged(window, bounds, bounds);
}
void WindowTreeClient::UnregisterFrameSinkId(WindowMus* window) {
@@ -527,7 +523,7 @@ WindowMus* WindowTreeClient::NewWindowFromWindowData(
SetWindowType(window, GetWindowTypeFromProperties(properties));
window->Init(ui::LAYER_NOT_DRAWN);
SetLocalPropertiesFromServerProperties(window_mus, window_data);
- window_mus->SetBoundsFromServer(window_data.bounds, base::nullopt);
+ window_mus->SetBoundsFromServer(window_data.bounds);
if (parent)
parent->AddChildFromServer(window_port_mus_ptr);
if (window_data.visible)
@@ -557,6 +553,8 @@ void WindowTreeClient::WindowTreeConnectionEstablished(
Env::GetInstance()->SetGestureRecognizer(
std::make_unique<GestureRecognizerImplMus>(this));
gesture_synchronizer_ = std::make_unique<GestureSynchronizer>(tree_);
+ client_side_window_move_handler_ =
+ std::make_unique<ClientSideWindowMoveHandler>(Env::GetInstance());
}
void WindowTreeClient::OnConnectionLost() {
@@ -640,7 +638,7 @@ void WindowTreeClient::SetWindowBoundsFromServer(
return;
}
- window->SetBoundsFromServer(revert_bounds, local_surface_id);
+ window->SetBoundsFromServer(revert_bounds);
}
void WindowTreeClient::SetWindowTransformFromServer(
@@ -681,12 +679,10 @@ void WindowTreeClient::ScheduleInFlightBoundsChange(
this, window, old_bounds,
window->GetLocalSurfaceIdAllocation().local_surface_id()));
base::Optional<viz::LocalSurfaceId> local_surface_id;
- if (window->GetWindow()->IsEmbeddingClient() ||
- window->HasLocalLayerTreeFrameSink()) {
- // Do not use ConvertRectToPixel, enclosing rects cause problems.
- const gfx::Size size = gfx::ScaleToCeiledSize(
- new_bounds.size(), window->GetDeviceScaleFactor());
- local_surface_id = window->GetOrAllocateLocalSurfaceId(size);
+ if (window->HasLocalSurfaceId()) {
+ local_surface_id = window->GetLocalSurfaceIdAllocation().local_surface_id();
+ DCHECK(local_surface_id);
+ DCHECK(local_surface_id->is_valid());
// |window_tree_host| may be null if this is called during creation of
// the window associated with the WindowTreeHostMus, or if there is an
// embedding.
@@ -1368,7 +1364,7 @@ void WindowTreeClient::OnWindowFocused(ws::Id focused_window_id) {
}
void WindowTreeClient::OnWindowCursorChanged(ws::Id window_id,
- ui::CursorData cursor) {
+ ui::Cursor cursor) {
WindowMus* window = GetWindowByServerId(window_id);
if (!window)
return;
@@ -1387,20 +1383,24 @@ void WindowTreeClient::OnDragDropStart(
void WindowTreeClient::OnDragEnter(ws::Id window_id,
uint32_t key_state,
- const gfx::Point& position,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask,
OnDragEnterCallback callback) {
std::move(callback).Run(drag_drop_controller_->OnDragEnter(
- GetWindowByServerId(window_id), key_state, position, effect_bitmask));
+ GetWindowByServerId(window_id), key_state, location_in_root, location,
+ effect_bitmask));
}
void WindowTreeClient::OnDragOver(ws::Id window_id,
uint32_t key_state,
- const gfx::Point& position,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask,
OnDragOverCallback callback) {
std::move(callback).Run(drag_drop_controller_->OnDragOver(
- GetWindowByServerId(window_id), key_state, position, effect_bitmask));
+ GetWindowByServerId(window_id), key_state, location_in_root, location,
+ effect_bitmask));
}
void WindowTreeClient::OnDragLeave(ws::Id window_id) {
@@ -1413,11 +1413,13 @@ void WindowTreeClient::OnDragDropDone() {
void WindowTreeClient::OnCompleteDrop(ws::Id window_id,
uint32_t key_state,
- const gfx::Point& position,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask,
OnCompleteDropCallback callback) {
std::move(callback).Run(drag_drop_controller_->OnCompleteDrop(
- GetWindowByServerId(window_id), key_state, position, effect_bitmask));
+ GetWindowByServerId(window_id), key_state, location_in_root, location,
+ effect_bitmask));
}
void WindowTreeClient::OnPerformDragDropCompleted(uint32_t change_id,
@@ -1468,8 +1470,7 @@ void WindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) {
// is deleted, but still we want to invoke the finished callback.
if (change_id == current_move_loop_change_) {
current_move_loop_change_ = 0;
- on_current_move_finished_.Run(success);
- on_current_move_finished_.Reset();
+ std::move(on_current_move_finished_).Run(success);
for (auto& observer : observers_)
observer.OnWindowMoveEnded(success);
}
@@ -1500,15 +1501,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;
+void WindowTreeClient::OnOcclusionStatesChanged(
+ const base::flat_map<ws::Id, ws::mojom::OcclusionState>&
+ occlusion_changes) {
+ for (const auto& change : occlusion_changes) {
+ WindowMus* window = GetWindowByServerId(change.first);
+ if (!window)
+ continue;
- WindowPortMus::Get(window->GetWindow())
- ->SetOcclusionStateFromServer(occlusion_state);
+ WindowPortMus::Get(window->GetWindow())
+ ->SetOcclusionStateFromServer(change.second);
+ }
}
void WindowTreeClient::OnDisplaysChanged(
@@ -1534,6 +1537,11 @@ void WindowTreeClient::RequestClose(ws::Id window_id) {
void WindowTreeClient::OnWindowTreeHostBoundsWillChange(
WindowTreeHostMus* window_tree_host,
const gfx::Rect& bounds_in_pixels) {
+ // The only other type of window that may hit this code path is EMBED. Clients
+ // are not allowed to change the bounds of EMBED windows (only the server).
+ // LOCAL and OTHER types don't have a WindowTreeHost.
+ DCHECK_EQ(WindowMusType::TOP_LEVEL,
+ WindowMus::Get(window_tree_host->window())->window_mus_type());
gfx::Rect old_bounds = window_tree_host->GetBoundsInPixels();
gfx::Rect new_bounds = bounds_in_pixels;
const float device_scale_factor = window_tree_host->device_scale_factor();
@@ -1590,9 +1598,9 @@ void WindowTreeClient::OnWindowTreeHostPerformWindowMove(
WindowTreeHostMus* window_tree_host,
ws::mojom::MoveLoopSource source,
const gfx::Point& cursor_location,
- const base::Callback<void(bool)>& callback) {
+ base::OnceCallback<void(bool)> callback) {
DCHECK(on_current_move_finished_.is_null());
- on_current_move_finished_ = callback;
+ on_current_move_finished_ = std::move(callback);
WindowMus* window_mus = WindowMus::Get(window_tree_host->window());
current_move_loop_change_ = ScheduleInFlightChange(
diff --git a/chromium/ui/aura/mus/window_tree_client.h b/chromium/ui/aura/mus/window_tree_client.h
index 186f8e5c173..c25d30f3995 100644
--- a/chromium/ui/aura/mus/window_tree_client.h
+++ b/chromium/ui/aura/mus/window_tree_client.h
@@ -58,6 +58,7 @@ class Gpu;
namespace aura {
class CaptureSynchronizer;
+class ClientSideWindowMoveHandler;
class DragDropControllerMus;
class EmbedRoot;
class EmbedRootDelegate;
@@ -135,8 +136,8 @@ class AURA_EXPORT WindowTreeClient
void SetEventTargetingPolicy(WindowMus* window,
ws::mojom::EventTargetingPolicy policy);
void SetCursor(WindowMus* window,
- const ui::CursorData& old_cursor,
- const ui::CursorData& new_cursor);
+ const ui::Cursor& old_cursor,
+ const ui::Cursor& new_cursor);
void SetWindowTextInputState(WindowMus* window,
ui::mojom::TextInputStatePtr state);
void SetImeVisibility(WindowMus* window,
@@ -220,6 +221,7 @@ class AURA_EXPORT WindowTreeClient
friend class InFlightPropertyChange;
friend class InFlightTransformChange;
friend class InFlightVisibleChange;
+ friend class ParentAllocator; // For OnWindowMusBoundsChanged().
friend class TopmostWindowTracker;
friend class WindowPortMus;
friend class WindowTreeClientTestApi;
@@ -431,23 +433,26 @@ class AURA_EXPORT WindowTreeClient
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 OnWindowCursorChanged(ws::Id window_id, ui::Cursor cursor) override;
void OnDragDropStart(const base::flat_map<std::string, std::vector<uint8_t>>&
mime_data) override;
void OnDragEnter(ws::Id window_id,
uint32_t event_flags,
- const gfx::Point& position,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask,
OnDragEnterCallback callback) override;
void OnDragOver(ws::Id window_id,
uint32_t event_flags,
- const gfx::Point& position,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask,
OnDragOverCallback callback) override;
void OnDragLeave(ws::Id window_id) override;
void OnCompleteDrop(ws::Id window_id,
uint32_t event_flags,
- const gfx::Point& position,
+ const gfx::PointF& location_in_root,
+ const gfx::PointF& location,
uint32_t effect_bitmask,
OnCompleteDropCallback callback) override;
void OnPerformDragDropCompleted(uint32_t change_id,
@@ -459,9 +464,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;
+ void OnOcclusionStatesChanged(
+ const base::flat_map<ws::Id, ws::mojom::OcclusionState>&
+ occlusion_changes) override;
// ws::mojom::ScreenProviderObserver:
void OnDisplaysChanged(std::vector<ws::mojom::WsDisplayPtr> ws_displays,
@@ -488,7 +493,7 @@ class AURA_EXPORT WindowTreeClient
WindowTreeHostMus* window_tree_host,
ws::mojom::MoveLoopSource mus_source,
const gfx::Point& cursor_location,
- const base::Callback<void(bool)>& callback) override;
+ base::OnceCallback<void(bool)> callback) override;
void OnWindowTreeHostCancelWindowMove(
WindowTreeHostMus* window_tree_host) override;
std::unique_ptr<WindowPortMus> CreateWindowPortForTopLevel(
@@ -541,6 +546,8 @@ class AURA_EXPORT WindowTreeClient
std::unique_ptr<GestureSynchronizer> gesture_synchronizer_;
+ std::unique_ptr<ClientSideWindowMoveHandler> client_side_window_move_handler_;
+
mojo::Binding<ws::mojom::WindowTreeClient> binding_;
ws::mojom::WindowTreePtr tree_ptr_;
// Typically this is the value contained in |tree_ptr_|, but tests may
@@ -568,7 +575,7 @@ class AURA_EXPORT WindowTreeClient
// Callback executed when a move loop initiated by PerformWindowMove() is
// completed.
- base::Callback<void(bool)> on_current_move_finished_;
+ base::OnceCallback<void(bool)> on_current_move_finished_;
std::unique_ptr<DragDropControllerMus> drag_drop_controller_;
diff --git a/chromium/ui/aura/mus/window_tree_client_unittest.cc b/chromium/ui/aura/mus/window_tree_client_unittest.cc
index 03c3b55880c..e120e0677f0 100644
--- a/chromium/ui/aura/mus/window_tree_client_unittest.cc
+++ b/chromium/ui/aura/mus/window_tree_client_unittest.cc
@@ -8,8 +8,8 @@
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
@@ -255,6 +255,9 @@ TEST_F(WindowTreeClientTest, SetBoundsFailedLocalSurfaceId) {
Window window(nullptr);
window.Init(ui::LAYER_NOT_DRAWN);
WindowPortMusTestHelper(&window).SimulateEmbedding();
+ // SimulateEmbedding() generates a bounds change.
+ ASSERT_TRUE(
+ window_tree()->AckSingleChangeOfType(WindowTreeChangeType::BOUNDS, true));
const gfx::Rect original_bounds(window.bounds());
const viz::LocalSurfaceId original_local_surface_id(
@@ -265,14 +268,19 @@ TEST_F(WindowTreeClientTest, SetBoundsFailedLocalSurfaceId) {
EXPECT_EQ(new_bounds, window.bounds());
WindowMus* window_mus = WindowMus::Get(&window);
ASSERT_NE(nullptr, window_mus);
- EXPECT_TRUE(window_mus->GetLocalSurfaceIdAllocation().IsValid());
+ ASSERT_TRUE(window_mus->GetLocalSurfaceIdAllocation().IsValid());
+ const viz::LocalSurfaceId new_surface_id =
+ window_mus->GetLocalSurfaceIdAllocation().local_surface_id();
// Reverting the change should also revert the viz::LocalSurfaceId.
ASSERT_TRUE(window_tree()->AckSingleChangeOfType(WindowTreeChangeType::BOUNDS,
false));
EXPECT_EQ(original_bounds, window.bounds());
- EXPECT_EQ(original_local_surface_id,
+ // Whenever the bounds changes a new LocalSurfaceId needs to be allocated.
+ EXPECT_NE(new_surface_id,
window.GetLocalSurfaceIdAllocation().local_surface_id());
+ EXPECT_EQ(1u,
+ window_tree()->GetChangeCountForType(WindowTreeChangeType::BOUNDS));
}
INSTANTIATE_TEST_CASE_P(/* no prefix */,
@@ -283,14 +291,15 @@ INSTANTIATE_TEST_CASE_P(/* no prefix */,
TEST_P(WindowTreeClientTestSurfaceSync, ClientSurfaceEmbedderCreated) {
Window window(nullptr);
window.Init(ui::LAYER_NOT_DRAWN);
- WindowPortMusTestHelper(&window).SimulateEmbedding();
- WindowPortMus* window_port_mus = WindowPortMus::Get(&window);
- ASSERT_NE(nullptr, window_port_mus);
+ WindowPortMusTestHelper window_test_helper(&window);
+
+ // A ClientSurfaceEmbedder is only created once there is an embedding.
+ ClientSurfaceEmbedder* client_surface_embedder =
+ window_test_helper.GetClientSurfaceEmbedder();
+ EXPECT_EQ(nullptr, client_surface_embedder);
+ window_test_helper.SimulateEmbedding();
- // A ClientSurfaceEmbedder is only created once there is bounds and a
- // FrameSinkId.
- EXPECT_EQ(nullptr, window_port_mus->client_surface_embedder());
gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100));
ASSERT_NE(new_bounds, window.bounds());
window.SetBounds(new_bounds);
@@ -298,8 +307,7 @@ TEST_P(WindowTreeClientTestSurfaceSync, ClientSurfaceEmbedderCreated) {
EXPECT_TRUE(WindowMus::Get(&window)->GetLocalSurfaceIdAllocation().IsValid());
// Once the bounds have been set, the ClientSurfaceEmbedder should be created.
- ClientSurfaceEmbedder* client_surface_embedder =
- window_port_mus->client_surface_embedder();
+ client_surface_embedder = window_test_helper.GetClientSurfaceEmbedder();
ASSERT_NE(nullptr, client_surface_embedder);
EXPECT_EQ(nullptr, client_surface_embedder->BottomGutterForTesting());
@@ -462,8 +470,7 @@ TEST_F(WindowTreeClientTest, FocusFromServer) {
// Simulates a bounds change, and while the bounds change is in flight the
// server replies with a new bounds and the original bounds change fails.
-// The server bounds change takes hold along with the associated
-// viz::LocalSurfaceId.
+// The server bounds change takes hold.
TEST_F(WindowTreeClientTest, SetBoundsFailedWithPendingChange) {
aura::Window root_window(nullptr);
root_window.Init(ui::LAYER_NOT_DRAWN);
@@ -492,15 +499,12 @@ TEST_F(WindowTreeClientTest, SetBoundsFailedWithPendingChange) {
ASSERT_TRUE(window_tree()->AckSingleChangeOfType(WindowTreeChangeType::BOUNDS,
false));
EXPECT_EQ(server_changed_bounds, root_window.bounds());
- EXPECT_EQ(server_changed_local_surface_id,
- 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->GetLocalSurfaceIdAllocation().IsValid());
}
TEST_F(WindowTreeClientTest, TwoInFlightBoundsChangesBothCanceled) {
@@ -2307,7 +2311,7 @@ TEST_F(WindowTreeClientTest, ModalTypeSuccess) {
// MODAL_TYPE_NONE, and make sure it succeeds each time.
ui::ModalType kModalTypes[] = {ui::MODAL_TYPE_WINDOW, ui::MODAL_TYPE_SYSTEM,
ui::MODAL_TYPE_NONE};
- for (size_t i = 0; i < arraysize(kModalTypes); i++) {
+ for (size_t i = 0; i < base::size(kModalTypes); i++) {
window.SetProperty(client::kModalKey, kModalTypes[i]);
// Ack change as succeeding.
ASSERT_TRUE(window_tree()->AckSingleChangeOfType(
@@ -2585,8 +2589,8 @@ TEST_F(WindowTreeClientTest, PerformWindowMove) {
WindowTreeHostMus* host_mus = static_cast<WindowTreeHostMus*>(host());
host_mus->PerformWindowMove(
- ws::mojom::MoveLoopSource::MOUSE, gfx::Point(),
- base::Bind(&OnWindowMoveDone, &call_count, &last_result));
+ host_mus->window(), ws::mojom::MoveLoopSource::MOUSE, gfx::Point(),
+ base::BindOnce(&OnWindowMoveDone, &call_count, &last_result));
EXPECT_EQ(0, call_count);
window_tree()->AckAllChanges();
@@ -2594,8 +2598,8 @@ TEST_F(WindowTreeClientTest, PerformWindowMove) {
EXPECT_TRUE(last_result);
host_mus->PerformWindowMove(
- ws::mojom::MoveLoopSource::MOUSE, gfx::Point(),
- base::Bind(&OnWindowMoveDone, &call_count, &last_result));
+ host_mus->window(), ws::mojom::MoveLoopSource::MOUSE, gfx::Point(),
+ base::BindOnce(&OnWindowMoveDone, &call_count, &last_result));
window_tree()->AckAllChangesOfType(WindowTreeChangeType::OTHER, false);
EXPECT_EQ(2, call_count);
EXPECT_FALSE(last_result);
@@ -2611,8 +2615,8 @@ TEST_F(WindowTreeClientTest, PerformWindowMoveDoneAfterDelete) {
window_tree()->AckAllChanges();
host_mus->PerformWindowMove(
- ws::mojom::MoveLoopSource::MOUSE, gfx::Point(),
- base::Bind(&OnWindowMoveDone, &call_count, &last_result));
+ host_mus->window(), ws::mojom::MoveLoopSource::MOUSE, gfx::Point(),
+ base::BindOnce(&OnWindowMoveDone, &call_count, &last_result));
EXPECT_EQ(0, call_count);
host_mus.reset();
@@ -2622,6 +2626,32 @@ TEST_F(WindowTreeClientTest, PerformWindowMoveDoneAfterDelete) {
EXPECT_TRUE(last_result);
}
+TEST_F(WindowTreeClientTest, PerformWindowMoveTransferEvents) {
+ int call_count = 0;
+ bool last_result = false;
+
+ aura::Window* window = CreateNormalWindow(10, host()->window(), nullptr);
+ WindowTreeHostMus* host_mus = static_cast<WindowTreeHostMus*>(host());
+ window->SetCapture();
+ host_mus->PerformWindowMove(
+ window, ws::mojom::MoveLoopSource::TOUCH, gfx::Point(),
+ base::BindOnce(&OnWindowMoveDone, &call_count, &last_result));
+ EXPECT_EQ(0, call_count);
+ EXPECT_EQ(WindowPortMus::Get(window)->server_id(),
+ window_tree()->last_transfer_current());
+ EXPECT_EQ(WindowPortMus::Get(host_mus->window())->server_id(),
+ window_tree()->last_transfer_new());
+ EXPECT_FALSE(window->HasCapture());
+
+ window_tree()->AckAllChanges();
+ EXPECT_EQ(1, call_count);
+ EXPECT_TRUE(last_result);
+ EXPECT_EQ(WindowPortMus::Get(host_mus->window())->server_id(),
+ window_tree()->last_transfer_current());
+ EXPECT_EQ(WindowPortMus::Get(window)->server_id(),
+ window_tree()->last_transfer_new());
+}
+
// Verifies occlusion state from server is applied to underlying window.
TEST_F(WindowTreeClientTest, OcclusionStateFromServer) {
struct {
@@ -2666,8 +2696,8 @@ TEST_F(WindowTreeClientTest, OcclusionStateFromServer) {
window.Hide();
}
- window_tree_client()->OnOcclusionStateChanged(
- server_id(&window), test.changed_state_from_server);
+ window_tree_client()->OnOcclusionStatesChanged(
+ {{server_id(&window), test.changed_state_from_server}});
EXPECT_EQ(test.expected_state, window.occlusion_state()) << test.name;
}
}
diff --git a/chromium/ui/aura/mus/window_tree_host_mus.cc b/chromium/ui/aura/mus/window_tree_host_mus.cc
index b6c7b101fa6..527e13ec0a6 100644
--- a/chromium/ui/aura/mus/window_tree_host_mus.cc
+++ b/chromium/ui/aura/mus/window_tree_host_mus.cc
@@ -4,6 +4,8 @@
#include "ui/aura/mus/window_tree_host_mus.h"
+#include <limits>
+
#include "ui/aura/env.h"
#include "ui/aura/mus/input_method_mus.h"
#include "ui/aura/mus/window_port_mus.h"
@@ -12,13 +14,17 @@
#include "ui/aura/mus/window_tree_host_mus_init_params.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tracker.h"
#include "ui/aura/window_tree_host_observer.h"
#include "ui/base/class_property.h"
+#include "ui/base/hit_test.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#include "ui/events/gestures/gesture_recognizer_observer.h"
#include "ui/platform_window/stub/stub_window.h"
DEFINE_UI_CLASS_PROPERTY_TYPE(aura::WindowTreeHostMus*);
@@ -30,7 +36,66 @@ namespace {
DEFINE_UI_CLASS_PROPERTY_KEY(
WindowTreeHostMus*, kWindowTreeHostMusKey, nullptr);
-static uint32_t accelerated_widget_count = 1;
+// Start at the max and decrease as in SingleProcessMash these values must not
+// overlap with values assigned by Ozone's PlatformWindow (which starts at 1
+// and increases).
+uint32_t next_accelerated_widget_id = std::numeric_limits<uint32_t>::max();
+
+// 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(Window* source, 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) {
+ Window* source = tracker_.Pop();
+ 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;
+ Window* dest = tracker_.windows()[1];
+ if (current_consumer == dest)
+ tracker_.Remove(dest);
+ }
+ void OnActiveTouchesCanceled(ui::GestureConsumer* consumer) override {}
+
+ WindowTracker tracker_;
+
+ ui::GestureRecognizer* gesture_recognizer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTouchTransferController);
+};
+
+void OnPerformWindowMoveDone(
+ std::unique_ptr<ScopedTouchTransferController> controller,
+ base::OnceCallback<void(bool)> callback,
+ bool success) {
+ controller.reset();
+ std::move(callback).Run(success);
+}
} // namespace
@@ -57,20 +122,20 @@ WindowTreeHostMus::WindowTreeHostMus(WindowTreeHostMusInitParams init_params)
// In other cases, let a valid FrameSinkId be selected by
// context_factory_private().
const bool force_software_compositor = false;
- const bool external_begin_frames_enabled = false;
+ ui::ExternalBeginFrameClient* external_begin_frame_client = nullptr;
const bool are_events_in_pixels = false;
CreateCompositor(window_mus->GenerateFrameSinkIdFromServerId(),
- force_software_compositor, external_begin_frames_enabled,
+ force_software_compositor, external_begin_frame_client,
are_events_in_pixels);
gfx::AcceleratedWidget accelerated_widget;
// We need accelerated widget numbers to be different for each window and
// fit in the smallest sizeof(AcceleratedWidget) uint32_t has this property.
#if defined(OS_WIN) || defined(OS_ANDROID)
accelerated_widget =
- reinterpret_cast<gfx::AcceleratedWidget>(accelerated_widget_count++);
+ reinterpret_cast<gfx::AcceleratedWidget>(next_accelerated_widget_id--);
#else
accelerated_widget =
- static_cast<gfx::AcceleratedWidget>(accelerated_widget_count++);
+ static_cast<gfx::AcceleratedWidget>(next_accelerated_widget_id--);
#endif
OnAcceleratedWidgetAvailable(accelerated_widget);
@@ -150,11 +215,21 @@ void WindowTreeHostMus::StackAtTop() {
}
void WindowTreeHostMus::PerformWindowMove(
+ Window* content_window,
ws::mojom::MoveLoopSource mus_source,
const gfx::Point& cursor_location,
- const base::Callback<void(bool)>& callback) {
+ base::OnceCallback<void(bool)> callback) {
+ DCHECK(window()->Contains(content_window));
+ std::unique_ptr<ScopedTouchTransferController> scoped_controller;
+ if (content_window != window()) {
+ scoped_controller = std::make_unique<ScopedTouchTransferController>(
+ content_window, window());
+ }
+ content_window->ReleaseCapture();
delegate_->OnWindowTreeHostPerformWindowMove(
- this, mus_source, cursor_location, callback);
+ this, mus_source, cursor_location,
+ base::BindOnce(&OnPerformWindowMoveDone, std::move(scoped_controller),
+ std::move(callback)));
}
void WindowTreeHostMus::CancelWindowMove() {
diff --git a/chromium/ui/aura/mus/window_tree_host_mus.h b/chromium/ui/aura/mus/window_tree_host_mus.h
index c8c9b9f9507..8a6d69592f9 100644
--- a/chromium/ui/aura/mus/window_tree_host_mus.h
+++ b/chromium/ui/aura/mus/window_tree_host_mus.h
@@ -70,9 +70,10 @@ class AURA_EXPORT WindowTreeHostMus : public WindowTreeHostPlatform,
// Tells the window manager to take control of moving the window. Returns
// true if the move wasn't canceled.
- void PerformWindowMove(ws::mojom::MoveLoopSource mus_source,
+ void PerformWindowMove(Window* window,
+ ws::mojom::MoveLoopSource mus_source,
const gfx::Point& cursor_location,
- const base::Callback<void(bool)>& callback);
+ base::OnceCallback<void(bool)> callback);
// Tells the window manager to abort any current move initiated by
// PerformWindowMove().
diff --git a/chromium/ui/aura/mus/window_tree_host_mus_delegate.h b/chromium/ui/aura/mus/window_tree_host_mus_delegate.h
index 0c17643cca5..399f55ef35e 100644
--- a/chromium/ui/aura/mus/window_tree_host_mus_delegate.h
+++ b/chromium/ui/aura/mus/window_tree_host_mus_delegate.h
@@ -60,7 +60,7 @@ class AURA_EXPORT WindowTreeHostMusDelegate {
WindowTreeHostMus* window_tree_host,
ws::mojom::MoveLoopSource mus_source,
const gfx::Point& cursor_location,
- const base::Callback<void(bool)>& callback) = 0;
+ base::OnceCallback<void(bool)> callback) = 0;
// Called to cancel a move loop.
virtual void OnWindowTreeHostCancelWindowMove(
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_win.cc b/chromium/ui/aura/native_window_occlusion_tracker_win.cc
index b0372b96bb5..a6442f0a1c7 100644
--- a/chromium/ui/aura/native_window_occlusion_tracker_win.cc
+++ b/chromium/ui/aura/native_window_occlusion_tracker_win.cc
@@ -168,17 +168,20 @@ bool NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque(
void NativeWindowOcclusionTrackerWin::UpdateOcclusionState(
const base::flat_map<HWND, Window::OcclusionState>&
root_window_hwnds_occlusion_state) {
+ num_visible_root_windows_ = 0;
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.
+ bool root_window_hidden = !it->second->IsVisible();
it->second->GetHost()->SetNativeWindowOcclusionState(
- !root_window->IsVisible() ? Window::OcclusionState::HIDDEN
- : root_window_pair.second);
+ root_window_hidden ? Window::OcclusionState::HIDDEN
+ : root_window_pair.second);
+ if (!root_window_hidden)
+ num_visible_root_windows_++;
}
}
@@ -223,9 +226,12 @@ 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)
+ // which case we need to register event hooks, and make sure that an
+ // occlusion calculation is scheduled.
+ if (visible) {
MaybeRegisterEventHooks();
+ ScheduleOcclusionCalculationIfNeeded();
+ }
}
void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_win.h b/chromium/ui/aura/native_window_occlusion_tracker_win.h
index 477e77ab0d0..238e4bf9338 100644
--- a/chromium/ui/aura/native_window_occlusion_tracker_win.h
+++ b/chromium/ui/aura/native_window_occlusion_tracker_win.h
@@ -207,6 +207,9 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver {
// |root_window_hwnds_occlusion_state_|.
base::flat_map<HWND, Window*> hwnd_root_window_map_;
+ // This is set by UpdateOcclusionState. It is currently only used by tests.
+ int num_visible_root_windows_ = 0;
+
std::unique_ptr<WindowOcclusionCalculator> occlusion_calculator_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowOcclusionTrackerWin);
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
index 674a2a90d76..e66f1369dc7 100644
--- a/chromium/ui/aura/native_window_occlusion_tracker_win_interactive_test.cc
+++ b/chromium/ui/aura/native_window_occlusion_tracker_win_interactive_test.cc
@@ -48,16 +48,20 @@ class MockWindowTreeHostObserver : public WindowTreeHostObserver {
// 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_) {
+ if (expectation_ != Window::OcclusionState::UNKNOWN &&
+ cur_state_ == expectation_) {
EXPECT_FALSE(quit_closure_.is_null());
std::move(quit_closure_).Run();
}
}
+ void set_quit_closure(base::OnceClosure quit_closure) {
+ quit_closure_ = std::move(quit_closure);
+ }
+
void set_expectation(Window::OcclusionState expectation) {
expectation_ = expectation;
}
@@ -163,6 +167,11 @@ class NativeWindowOcclusionTrackerTest : public test::AuraTestBase {
window->env()->GetWindowOcclusionTracker()->Track(window);
}
+ int GetNumVisibleRootWindows() {
+ return NativeWindowOcclusionTrackerWin::GetOrCreateInstance()
+ ->num_visible_root_windows_;
+ }
+
private:
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<TestNativeWindow> native_win_;
@@ -200,12 +209,60 @@ TEST_F(NativeWindowOcclusionTrackerTest, SimpleHidden) {
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
+ // Iconify the tracked aura window and check that its occlusion state
// is HIDDEN.
- ::ShowWindow(host()->GetAcceleratedWidget(), SW_MINIMIZE);
+ CloseWindow(host()->GetAcceleratedWidget());
observer.set_expectation(Window::OcclusionState::HIDDEN);
run_loop.Run();
EXPECT_FALSE(observer.is_expecting_call());
}
+// Test that minimizing and restoring an app window results in the occlusion
+// tracker re-registering for win events and detecting that a native window
+// occludes the app window.
+TEST_F(NativeWindowOcclusionTrackerTest, OcclusionAfterVisibilityToggle) {
+ base::RunLoop run_loop;
+ MockWindowTreeHostObserver observer(run_loop.QuitClosure());
+ CreateTrackedAuraWindowWithBounds(&observer, gfx::Rect(0, 0, 100, 100));
+ observer.set_expectation(Window::OcclusionState::VISIBLE);
+ run_loop.Run();
+
+ base::RunLoop run_loop2;
+ observer.set_expectation(Window::OcclusionState::HIDDEN);
+ observer.set_quit_closure(run_loop2.QuitClosure());
+ // host()->window()->Hide() is needed to generate OnWindowVisibilityChanged
+ // notifications.
+ host()->window()->Hide();
+ // This makes the window iconic.
+ ::CloseWindow(host()->GetAcceleratedWidget());
+ run_loop2.Run();
+ // HIDDEN state is set synchronously by OnWindowVsiblityChanged notification,
+ // before occlusion is calculated, so the above expectation will be met w/o an
+ // occlusion calculation.
+ // Loop until an occlusion calculation has run with no non-hidden app windows.
+
+ do {
+ // Need to pump events in order for UpdateOcclusionState to get called, and
+ // update the number of non hidden root windows. When that number is 0,
+ // occlusion has been calculated with no visible root windows.
+ base::RunLoop().RunUntilIdle();
+ } while (GetNumVisibleRootWindows() != 0);
+
+ base::RunLoop run_loop3;
+ observer.set_expectation(Window::OcclusionState::VISIBLE);
+ observer.set_quit_closure(run_loop3.QuitClosure());
+ host()->window()->Show();
+ // This opens the window made iconic above.
+ OpenIcon(host()->GetAcceleratedWidget());
+ run_loop3.Run();
+
+ // Open a native window that occludes the visible app window.
+ base::RunLoop run_loop4;
+ observer.set_expectation(Window::OcclusionState::OCCLUDED);
+ observer.set_quit_closure(run_loop4.QuitClosure());
+ CreateNativeWindowWithBounds(gfx::Rect(0, 0, 100, 100));
+ run_loop4.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 2c6070f7207..f2bd4f979df 100644
--- a/chromium/ui/aura/test/ui_controls_factory_ozone.cc
+++ b/chromium/ui/aura/test/ui_controls_factory_ozone.cc
@@ -16,10 +16,12 @@
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/test/aura_test_utils.h"
#include "ui/aura/test/env_test_helper.h"
+#include "ui/aura/test/mus/window_tree_client_test_api.h"
#include "ui/aura/test/ui_controls_factory_aura.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/test/ui_controls_aura.h"
#include "ui/display/display.h"
+#include "ui/display/display_observer.h"
#include "ui/display/screen.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/events_test_utils.h"
@@ -28,18 +30,16 @@ namespace aura {
namespace test {
namespace {
-// Callback from Window Service with the result of posting an event. |result|
-// is true if event successfully processed and |closure| is an optional closure
-// to run when done (used in client code to wait for ack).
-void OnWindowServiceProcessedEvent(base::OnceClosure closure, bool result) {
- DCHECK(result);
- if (closure)
- std::move(closure).Run();
-}
-
-class UIControlsOzone : public ui_controls::UIControlsAura {
+class UIControlsOzone : public ui_controls::UIControlsAura,
+ display::DisplayObserver {
public:
- UIControlsOzone(WindowTreeHost* host) : host_(host) {}
+ UIControlsOzone(WindowTreeHost* host) : host_(host) {
+ MaybeInitializeEventInjector();
+ display::Screen::GetScreen()->AddObserver(this);
+ }
+ ~UIControlsOzone() override {
+ display::Screen::GetScreen()->RemoveObserver(this);
+ }
private:
// ui_controls::UIControlsAura:
@@ -60,40 +60,43 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
bool command,
base::OnceClosure closure) override {
int flags = button_down_mask_;
+ int64_t display_id =
+ display::Screen::GetScreen()->GetDisplayNearestWindow(window).id();
if (control) {
flags |= ui::EF_CONTROL_DOWN;
- PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, flags,
+ PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, flags, display_id,
base::OnceClosure());
}
if (shift) {
flags |= ui::EF_SHIFT_DOWN;
- PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, flags,
+ PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, flags, display_id,
base::OnceClosure());
}
if (alt) {
flags |= ui::EF_ALT_DOWN;
- PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_MENU, flags,
+ PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_MENU, flags, display_id,
base::OnceClosure());
}
if (command) {
flags |= ui::EF_COMMAND_DOWN;
- PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LWIN, flags,
+ PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LWIN, flags, display_id,
base::OnceClosure());
}
- PostKeyEvent(ui::ET_KEY_PRESSED, key, flags, base::OnceClosure());
+ PostKeyEvent(ui::ET_KEY_PRESSED, key, flags, display_id,
+ base::OnceClosure());
const bool has_modifier = control || shift || alt || command;
// Pass the real closure to the last generated KeyEvent.
- PostKeyEvent(ui::ET_KEY_RELEASED, key, flags,
+ PostKeyEvent(ui::ET_KEY_RELEASED, key, flags, display_id,
has_modifier ? base::OnceClosure() : std::move(closure));
if (alt) {
flags &= ~ui::EF_ALT_DOWN;
- PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_MENU, flags,
+ PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_MENU, flags, display_id,
(shift || control || command) ? base::OnceClosure()
: std::move(closure));
}
@@ -101,19 +104,19 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
if (shift) {
flags &= ~ui::EF_SHIFT_DOWN;
PostKeyEvent(
- ui::ET_KEY_RELEASED, ui::VKEY_SHIFT, flags,
+ ui::ET_KEY_RELEASED, ui::VKEY_SHIFT, flags, display_id,
(control || command) ? base::OnceClosure() : std::move(closure));
}
if (control) {
flags &= ~ui::EF_CONTROL_DOWN;
- PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL, flags,
+ PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL, flags, display_id,
command ? base::OnceClosure() : std::move(closure));
}
if (command) {
flags &= ~ui::EF_COMMAND_DOWN;
- PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_LWIN, flags,
+ PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_LWIN, flags, display_id,
std::move(closure));
}
@@ -127,9 +130,11 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
long screen_y,
base::OnceClosure closure) override {
gfx::Point host_location(screen_x, screen_y);
- if (!ScreenDIPToHostPixels(&host_location))
+ int64_t display_id = display::kInvalidDisplayId;
+ if (!ScreenDIPToHostPixels(&host_location, &display_id))
return false;
last_mouse_location_ = host_location;
+ last_mouse_display_id_ = display_id;
ui::EventType event_type;
@@ -138,7 +143,7 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
else
event_type = ui::ET_MOUSE_MOVED;
- PostMouseEvent(event_type, host_location, button_down_mask_, 0,
+ PostMouseEvent(event_type, host_location, button_down_mask_, 0, display_id,
std::move(closure));
return true;
@@ -154,11 +159,13 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
base::OnceClosure closure,
int accelerator_state) override {
gfx::Point host_location;
+ int64_t display_id = display::kInvalidDisplayId;
if (last_mouse_location_.has_value()) {
host_location = last_mouse_location_.value();
+ display_id = last_mouse_display_id_;
} else {
host_location = host_->window()->env()->last_mouse_location();
- if (!ScreenDIPToHostPixels(&host_location))
+ if (!ScreenDIPToHostPixels(&host_location, &display_id))
return false;
}
@@ -194,14 +201,14 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
button_down_mask_ |= flag;
// Pass the real closure to the last generated MouseEvent.
PostMouseEvent(ui::ET_MOUSE_PRESSED, host_location,
- button_down_mask_ | flag, changed_button_flag,
+ button_down_mask_ | flag, changed_button_flag, display_id,
(button_state & ui_controls::UP) ? base::OnceClosure()
: std::move(closure));
}
if (button_state & ui_controls::UP) {
button_down_mask_ &= ~flag;
PostMouseEvent(ui::ET_MOUSE_RELEASED, host_location,
- button_down_mask_ | flag, changed_button_flag,
+ button_down_mask_ | flag, changed_button_flag, display_id,
std::move(closure));
}
@@ -222,37 +229,42 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
base::OnceClosure task) override {
DCHECK_NE(0, action);
gfx::Point host_location(x, y);
- if (!ScreenDIPToHostPixels(&host_location))
+ int64_t display_id = display::kInvalidDisplayId;
+ if (!ScreenDIPToHostPixels(&host_location, &display_id))
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));
+ PostTouchEvent(
+ ui::ET_TOUCH_PRESSED, host_location, id, display_id,
+ (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));
+ PostTouchEvent(ui::ET_TOUCH_MOVED, host_location, id, display_id,
+ 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));
+ PostTouchEvent(ui::ET_TOUCH_RELEASED, host_location, id, display_id,
+ std::move(task));
}
return true;
}
#endif
- void SendEventToSink(ui::Event* event, base::OnceClosure closure) {
- if (host_->window()->env()->mode() == aura::Env::Mode::MUS) {
- GetEventInjector()->InjectEvent(
- host_->GetDisplayId(), ui::Event::Clone(*event),
+ // display::DisplayObserver:
+ void OnDisplayRemoved(const display::Display& old_display) override {
+ if (last_mouse_display_id_ == old_display.id()) {
+ last_mouse_display_id_ = display::kInvalidDisplayId;
+ last_mouse_location_.reset();
+ }
+ }
+
+ void SendEventToSink(ui::Event* event,
+ int64_t display_id,
+ base::OnceClosure closure) {
+ if (event_injector_) {
+ event_injector_->InjectEvent(
+ display_id, ui::Event::Clone(*event),
base::BindOnce(&OnWindowServiceProcessedEvent, std::move(closure)));
return;
}
@@ -271,40 +283,44 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
void PostKeyEvent(ui::EventType type,
ui::KeyboardCode key_code,
int flags,
+ int64_t display_id,
base::OnceClosure closure) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&UIControlsOzone::PostKeyEventTask,
base::Unretained(this), type, key_code, flags,
- std::move(closure)));
+ display_id, std::move(closure)));
}
void PostKeyEventTask(ui::EventType type,
ui::KeyboardCode key_code,
int flags,
+ int64_t display_id,
base::OnceClosure closure) {
// Do not rewrite injected events. See crbug.com/136465.
flags |= ui::EF_FINAL;
ui::KeyEvent key_event(type, key_code, flags);
- SendEventToSink(&key_event, std::move(closure));
+ SendEventToSink(&key_event, display_id, std::move(closure));
}
void PostMouseEvent(ui::EventType type,
const gfx::Point& host_location,
int flags,
int changed_button_flags,
+ int64_t display_id,
base::OnceClosure closure) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&UIControlsOzone::PostMouseEventTask,
base::Unretained(this), type, host_location, flags,
- changed_button_flags, std::move(closure)));
+ changed_button_flags, display_id, std::move(closure)));
}
void PostMouseEventTask(ui::EventType type,
const gfx::Point& host_location,
int flags,
int changed_button_flags,
+ int64_t display_id,
base::OnceClosure closure) {
ui::MouseEvent mouse_event(type, host_location, host_location,
ui::EventTimeForNow(), flags,
@@ -313,33 +329,57 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
// This hack is necessary to set the repeat count for clicks.
ui::MouseEvent mouse_event2(&mouse_event);
- SendEventToSink(&mouse_event2, std::move(closure));
+ SendEventToSink(&mouse_event2, display_id, std::move(closure));
}
- // Returns the ws::mojom::EventInjector, which is used to send events
- // to the Window Service for dispatch.
- ws::mojom::EventInjector* GetEventInjector() {
- DCHECK_EQ(aura::Env::Mode::MUS, host_->window()->env()->mode());
- if (!event_injector_) {
- DCHECK(aura::test::EnvTestHelper().GetWindowTreeClient());
- aura::test::EnvTestHelper()
- .GetWindowTreeClient()
- ->connector()
- ->BindInterface(ws::mojom::kServiceName, &event_injector_);
- }
- return event_injector_.get();
+ void PostTouchEvent(ui::EventType type,
+ const gfx::Point& host_location,
+ int id,
+ int64_t display_id,
+ base::OnceClosure closure) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&UIControlsOzone::PostTouchEventTask,
+ base::Unretained(this), type, host_location,
+ id, display_id, std::move(closure)));
}
- bool ScreenDIPToHostPixels(gfx::Point* location) {
+ void PostTouchEventTask(ui::EventType type,
+ const gfx::Point& host_location,
+ int id,
+ int64_t display_id,
+ base::OnceClosure closure) {
+ ui::PointerDetails details(ui::EventPointerType::POINTER_TYPE_TOUCH, id,
+ 1.0f, 1.0f, 0.0f);
+ ui::TouchEvent touch_event(type, host_location, ui::EventTimeForNow(),
+ details);
+ SendEventToSink(&touch_event, display_id, std::move(closure));
+ }
+
+ // Initializes EventInjector when Mus. Otherwise do nothing.
+ void MaybeInitializeEventInjector() {
+ if (host_->window()->env()->mode() != Env::Mode::MUS)
+ return;
+
+ DCHECK(aura::test::EnvTestHelper().GetWindowTreeClient());
+ aura::test::EnvTestHelper()
+ .GetWindowTreeClient()
+ ->connector()
+ ->BindInterface(ws::mojom::kServiceName, &event_injector_);
+ }
+
+ bool ScreenDIPToHostPixels(gfx::Point* location, int64_t* display_id) {
// 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();
+ display::Display display =
+ display::Screen::GetScreen()->GetDisplayNearestPoint(*location);
+ if (!display.is_valid()) {
+ LOG(ERROR) << "Failed to find the display for " << location->ToString();
return false;
}
+ *display_id = display.id();
*location -= display.bounds().OffsetFromOrigin();
- host_->ConvertDIPToPixels(location);
+ *location =
+ gfx::ScaleToFlooredPoint(*location, display.device_scale_factor(),
+ display.device_scale_factor());
return true;
}
@@ -351,6 +391,11 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
// is updated asynchronously with mus.
base::Optional<gfx::Point> last_mouse_location_;
+ // The display ID where the last SendMouseEventsNotifyWhenDone occurred. This
+ // is used along with |last_mouse_location_| to send the mouse event to the
+ // event injector. Not used when Mus is not enabled.
+ int64_t last_mouse_display_id_ = display::kInvalidDisplayId;
+
// Mask of the mouse buttons currently down. This is static as it needs to
// track the state globally for all displays. A UIControlsOzone instance is
// created for each display host.
@@ -368,5 +413,20 @@ ui_controls::UIControlsAura* CreateUIControlsAura(WindowTreeHost* host) {
return new UIControlsOzone(host);
}
+void OnWindowServiceProcessedEvent(base::OnceClosure closure, bool result) {
+ DCHECK(result);
+ if (closure) {
+ // There can be several mojo calls are queued in the window tree client,
+ // which may change the order of the operations unexpectedly. Do not call
+ // WaitForAllChangesToComplete() here, since some in-flight changes might
+ // not be resolved by just waiting (like window-dragging will not finish
+ // until it's cancelled or the mouse or touch is released).
+ // See also: https://crbug.com/916177
+ WindowTreeClientTestApi(EnvTestHelper().GetWindowTreeClient())
+ .FlushForTesting();
+ std::move(closure).Run();
+ }
+}
+
} // namespace test
} // namespace aura
diff --git a/chromium/ui/aura/window.cc b/chromium/ui/aura/window.cc
index ef148894298..972e0c5bd07 100644
--- a/chromium/ui/aura/window.cc
+++ b/chromium/ui/aura/window.cc
@@ -20,6 +20,7 @@
#include "base/strings/stringprintf.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/cursor_client.h"
@@ -48,7 +49,6 @@
#include "ui/events/event_target_iterator.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/scoped_canvas.h"
namespace aura {
@@ -317,9 +317,9 @@ std::unique_ptr<WindowTargeter> Window::SetEventTargeter(
}
void Window::SetBounds(const gfx::Rect& new_bounds) {
- if (parent_ && parent_->layout_manager())
+ if (parent_ && parent_->layout_manager()) {
parent_->layout_manager()->SetChildBounds(this, new_bounds);
- else {
+ } else {
// Ensure we don't go smaller than our minimum bounds.
gfx::Rect final_bounds(new_bounds);
if (delegate_) {
@@ -690,21 +690,6 @@ bool Window::CanFocus() const {
return parent_->CanFocus();
}
-bool Window::CanReceiveEvents() const {
- // TODO(sky): this may want to delegate to the WindowPort as for mus there
- // isn't a point in descending into windows owned by the client.
- if (IsRootWindow())
- return IsVisible();
-
- // The client may forbid certain windows from receiving events at a given
- // point in time.
- client::EventClient* client = client::GetEventClient(GetRootWindow());
- if (client && !client->CanProcessEventsWithinSubtree(this))
- return false;
-
- return parent_ && IsVisible() && parent_->CanReceiveEvents();
-}
-
void Window::SetCapture() {
if (!IsVisible())
return;
@@ -831,7 +816,7 @@ bool Window::HitTest(const gfx::Point& local_point) {
if (!delegate_ || !delegate_->HasHitTestMask())
return local_bounds.Contains(local_point);
- gfx::Path mask;
+ SkPath mask;
delegate_->GetHitTestMask(&mask);
SkRegion clip_region;
@@ -893,6 +878,9 @@ void Window::SetOcclusionInfo(OcclusionState occlusion_state,
occluded_region_ = occluded_region;
if (delegate_)
delegate_->OnWindowOcclusionChanged(occlusion_state, occluded_region);
+
+ for (WindowObserver& observer : observers_)
+ observer.OnWindowOcclusionChanged(this);
}
}
@@ -1058,7 +1046,7 @@ void Window::NotifyWindowHierarchyChangeAtReceiver(
void Window::NotifyWindowVisibilityChanged(aura::Window* target,
bool visible) {
if (!NotifyWindowVisibilityChangedDown(target, visible))
- return; // |this| has been deleted.
+ return; // |this| has been deleted.
NotifyWindowVisibilityChangedUp(target, visible);
}
@@ -1077,7 +1065,7 @@ bool Window::NotifyWindowVisibilityChangedAtReceiver(aura::Window* target,
bool Window::NotifyWindowVisibilityChangedDown(aura::Window* target,
bool visible) {
if (!NotifyWindowVisibilityChangedAtReceiver(target, visible))
- return false; // |this| was deleted.
+ return false; // |this| was deleted.
WindowTracker this_tracker;
this_tracker.Add(this);
diff --git a/chromium/ui/aura/window.h b/chromium/ui/aura/window.h
index 010edc94e27..7fbb0d6677e 100644
--- a/chromium/ui/aura/window.h
+++ b/chromium/ui/aura/window.h
@@ -356,9 +356,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Returns true if the Window can be focused.
bool CanFocus() const;
- // Returns true if the Window can receive events.
- bool CanReceiveEvents() const;
-
// Does a capture on the window. This does nothing if the window isn't showing
// (VISIBILITY_SHOWN) or isn't contained in a valid window hierarchy.
void SetCapture();
@@ -479,10 +476,10 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
int64_t old_value,
std::unique_ptr<ui::PropertyData> data) override;
private:
+ friend class DefaultWindowOcclusionChangeBuilder;
friend class HitTestDataProviderAura;
friend class LayoutManager;
friend class PropertyConverter;
- friend class WindowOcclusionTracker;
friend class WindowPort;
friend class WindowPortForShutdown;
friend class WindowPortMus;
@@ -663,7 +660,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> observers_;
+ base::ReentrantObserverList<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 8107a0d3b41..e25e9850990 100644
--- a/chromium/ui/aura/window_delegate.h
+++ b/chromium/ui/aura/window_delegate.h
@@ -13,8 +13,9 @@
#include "ui/events/event_handler.h"
#include "ui/gfx/native_widget_types.h"
+class SkPath;
+
namespace gfx {
-class Path;
class Point;
class Rect;
class Size;
@@ -101,7 +102,7 @@ class AURA_EXPORT WindowDelegate : public ui::EventHandler {
// Called from Window::HitTest to retrieve hit test mask when HasHitTestMask
// above returns true.
- virtual void GetHitTestMask(gfx::Path* mask) const = 0;
+ virtual void GetHitTestMask(SkPath* mask) const = 0;
// Returns whether the window wants to receive and handle double tap gesture
// events. Defaults to false.
diff --git a/chromium/ui/aura/window_event_dispatcher.cc b/chromium/ui/aura/window_event_dispatcher.cc
index f22e6d1f000..f95080f10c3 100644
--- a/chromium/ui/aura/window_event_dispatcher.cc
+++ b/chromium/ui/aura/window_event_dispatcher.cc
@@ -34,6 +34,7 @@
#include "ui/events/event_utils.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/events/gestures/gesture_types.h"
+#include "ui/events/platform/platform_event_source.h"
typedef ui::EventDispatchDetails DispatchDetails;
@@ -866,6 +867,11 @@ ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() {
}
void WindowEventDispatcher::PostSynthesizeMouseMove() {
+ // No one should care where the real mouse is when this flag is on. So there
+ // is no need to send a synthetic mouse move here.
+ if (ui::PlatformEventSource::ShouldIgnoreNativePlatformEvents())
+ return;
+
if (synthesize_mouse_move_ || in_shutdown_)
return;
synthesize_mouse_move_ = true;
diff --git a/chromium/ui/aura/window_event_dispatcher_unittest.cc b/chromium/ui/aura/window_event_dispatcher_unittest.cc
index 1e4680488c6..9475308e47b 100644
--- a/chromium/ui/aura/window_event_dispatcher_unittest.cc
+++ b/chromium/ui/aura/window_event_dispatcher_unittest.cc
@@ -139,8 +139,11 @@ TEST_P(WindowEventDispatcherTest, OnHostMouseEvent) {
ui::EF_LEFT_MOUSE_BUTTON);
DispatchEventUsingWindowDispatcher(&event1);
- // Event was tested for non-client area for the target window.
- EXPECT_EQ(1, delegate1->non_client_count());
+ // Event was tested for non-client area for the target window. The expected
+ // value is 2 when mode is MUS, since ClientSideWindowMoveHandler also invokes
+ // it.
+ EXPECT_EQ((Env::GetInstance()->mode() == Env::Mode::MUS) ? 2 : 1,
+ delegate1->non_client_count());
EXPECT_EQ(0, delegate2->non_client_count());
// The non-client component test was in local coordinates.
EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location());
diff --git a/chromium/ui/aura/window_observer.h b/chromium/ui/aura/window_observer.h
index 1da8e5fbacf..57e351893f9 100644
--- a/chromium/ui/aura/window_observer.h
+++ b/chromium/ui/aura/window_observer.h
@@ -174,6 +174,9 @@ class AURA_EXPORT WindowObserver : public base::CheckedObserver {
// embedded).
virtual void OnEmbeddedAppDisconnected(Window* window) {}
+ // Called when the occlusion state of |window| changes.
+ virtual void OnWindowOcclusionChanged(Window* window) {}
+
protected:
~WindowObserver() override;
};
diff --git a/chromium/ui/aura/window_occlusion_change_builder.cc b/chromium/ui/aura/window_occlusion_change_builder.cc
new file mode 100644
index 00000000000..23724a72745
--- /dev/null
+++ b/chromium/ui/aura/window_occlusion_change_builder.cc
@@ -0,0 +1,67 @@
+// 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/window_occlusion_change_builder.h"
+
+#include "base/containers/flat_map.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/aura/window_tracker.h"
+
+namespace aura {
+
+// Provide updating of occlusion info on aura::Window.
+class DefaultWindowOcclusionChangeBuilder
+ : public WindowOcclusionChangeBuilder {
+ public:
+ DefaultWindowOcclusionChangeBuilder() = default;
+ ~DefaultWindowOcclusionChangeBuilder() override {
+ while (!windows_.windows().empty()) {
+ Window* window = windows_.Pop();
+ auto it = changes_.find(window);
+ if (it == changes_.end())
+ continue;
+
+ window->SetOcclusionInfo(it->second.occlusion_state,
+ it->second.occluded_region);
+ }
+ changes_.clear();
+ }
+
+ private:
+ struct OcclusionData {
+ Window::OcclusionState occlusion_state;
+ SkRegion occluded_region;
+ };
+
+ // WindowOcclusionChangeBuilder:
+ void Add(Window* window,
+ Window::OcclusionState occlusion_state,
+ SkRegion occluded_region) override {
+ // Change back to UNKNOWN is not allowed.
+ DCHECK_NE(occlusion_state, Window::OcclusionState::UNKNOWN);
+
+ windows_.Add(window);
+ changes_[window] = {occlusion_state, occluded_region};
+ }
+
+ // Tracks live windows that has a change. This is needed in addition to the
+ // keys in |changes_| because the window tree may change while changes are
+ // accumulated or being applied.
+ WindowTracker windows_;
+
+ // Stores the accumulated occlusion changes.
+ base::flat_map<Window*, OcclusionData> changes_;
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultWindowOcclusionChangeBuilder);
+};
+
+// static
+std::unique_ptr<WindowOcclusionChangeBuilder>
+WindowOcclusionChangeBuilder::Create() {
+ return std::make_unique<DefaultWindowOcclusionChangeBuilder>();
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/window_occlusion_change_builder.h b/chromium/ui/aura/window_occlusion_change_builder.h
new file mode 100644
index 00000000000..05cd323b4db
--- /dev/null
+++ b/chromium/ui/aura/window_occlusion_change_builder.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_WINDOW_OCCLUSION_CHANGE_BUILDER_H_
+#define UI_AURA_WINDOW_OCCLUSION_CHANGE_BUILDER_H_
+
+#include <memory>
+
+#include "ui/aura/aura_export.h"
+#include "ui/aura/window.h"
+
+class SkRegion;
+
+namespace aura {
+
+// Interface for WindowOcclusionTracker to update window occlusion info.
+class AURA_EXPORT WindowOcclusionChangeBuilder {
+ public:
+ virtual ~WindowOcclusionChangeBuilder() = default;
+
+ // Add an occlusion info change for |window|.
+ // Note that setting Window::OcclusionState::UNKNOWN to a window is not
+ // allowed.
+ virtual void Add(Window* window,
+ Window::OcclusionState occlusion_state,
+ SkRegion occluded_region) = 0;
+
+ // Factory to create the default implementation that updates occlusion info
+ // on aura::Window.
+ static std::unique_ptr<WindowOcclusionChangeBuilder> Create();
+};
+
+} // namespace aura
+
+#endif // UI_AURA_WINDOW_OCCLUSION_CHANGE_BUILDER_H_
diff --git a/chromium/ui/aura/window_occlusion_change_builder_unittest.cc b/chromium/ui/aura/window_occlusion_change_builder_unittest.cc
new file mode 100644
index 00000000000..b972d5066f0
--- /dev/null
+++ b/chromium/ui/aura/window_occlusion_change_builder_unittest.cc
@@ -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.
+
+#include "ui/aura/window_occlusion_change_builder.h"
+
+#include <memory>
+
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_windows.h"
+
+namespace aura {
+
+namespace {
+
+// A delegate that remembers the occlusion info of its window.
+class OcclusionTrackWindowDelegate : public test::TestWindowDelegate {
+ public:
+ OcclusionTrackWindowDelegate() = default;
+ ~OcclusionTrackWindowDelegate() override = default;
+
+ bool occlusion_change_count() const { return occlusion_change_count_; }
+ Window::OcclusionState last_occlusion_state() const {
+ return last_occlusion_state_;
+ }
+ const SkRegion& last_occluded_region() const { return last_occluded_region_; }
+
+ private:
+ // test::TestWindowDelegate:
+ void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) override {
+ ++occlusion_change_count_;
+ last_occlusion_state_ = occlusion_state;
+ last_occluded_region_ = occluded_region;
+ }
+
+ int occlusion_change_count_ = 0;
+ Window::OcclusionState last_occlusion_state_ =
+ Window::OcclusionState::UNKNOWN;
+ SkRegion last_occluded_region_;
+
+ DISALLOW_COPY_AND_ASSIGN(OcclusionTrackWindowDelegate);
+};
+
+} // namespace
+
+class WindowOcclusionChangeBuilderTest : public test::AuraTestBase {
+ public:
+ WindowOcclusionChangeBuilderTest() = default;
+ ~WindowOcclusionChangeBuilderTest() override = default;
+
+ std::unique_ptr<Window> CreateTestWindow(
+ OcclusionTrackWindowDelegate* delegate) {
+ auto window = std::make_unique<Window>(delegate);
+ window->set_owned_by_parent(false);
+ window->SetType(client::WINDOW_TYPE_NORMAL);
+ window->Init(ui::LAYER_TEXTURED);
+ window->Show();
+
+ root_window()->AddChild(window.get());
+ return window;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WindowOcclusionChangeBuilderTest);
+};
+
+// Test that window occlusion info is updated after commit.
+TEST_F(WindowOcclusionChangeBuilderTest, SingleWindow) {
+ SkRegion region;
+ region.setRect(1, 2, 3, 4);
+
+ for (const auto state :
+ {Window::OcclusionState::VISIBLE, Window::OcclusionState::OCCLUDED,
+ Window::OcclusionState::HIDDEN}) {
+ OcclusionTrackWindowDelegate delegate;
+ auto window = CreateTestWindow(&delegate);
+
+ auto builder = WindowOcclusionChangeBuilder::Create();
+ builder->Add(window.get(), state, region);
+
+ // Change should not be applied before Commit call.
+ EXPECT_EQ(0, delegate.occlusion_change_count());
+
+ // All changes are committed when builder is released.
+ builder.reset();
+
+ EXPECT_EQ(1, delegate.occlusion_change_count());
+ EXPECT_EQ(state, delegate.last_occlusion_state());
+ EXPECT_EQ(region, delegate.last_occluded_region());
+ }
+}
+
+// Test updating multiple windows.
+TEST_F(WindowOcclusionChangeBuilderTest, MultipleWindow) {
+ auto builder = WindowOcclusionChangeBuilder::Create();
+
+ OcclusionTrackWindowDelegate delegate1;
+ auto window1 = CreateTestWindow(&delegate1);
+ const Window::OcclusionState state1 = Window::OcclusionState::VISIBLE;
+ SkRegion region1;
+ region1.setRect(1, 2, 3, 4);
+ builder->Add(window1.get(), state1, region1);
+
+ OcclusionTrackWindowDelegate delegate2;
+ auto window2 = CreateTestWindow(&delegate2);
+ const Window::OcclusionState state2 = Window::OcclusionState::OCCLUDED;
+ SkRegion region2;
+ region2.setRect(5, 6, 7, 8);
+ builder->Add(window2.get(), state2, region2);
+
+ // Changes should not be applied before Commit call.
+ EXPECT_EQ(0, delegate1.occlusion_change_count());
+ EXPECT_EQ(0, delegate2.occlusion_change_count());
+
+ // All changes are committed when builder is released.
+ builder.reset();
+
+ EXPECT_EQ(1, delegate1.occlusion_change_count());
+ EXPECT_EQ(state1, delegate1.last_occlusion_state());
+ EXPECT_EQ(region1, delegate1.last_occluded_region());
+
+ EXPECT_EQ(1, delegate2.occlusion_change_count());
+ EXPECT_EQ(state2, delegate2.last_occlusion_state());
+ EXPECT_EQ(region2, delegate2.last_occluded_region());
+}
+
+// Tests that the last change wins when there are multiple changes on the same
+// window.
+TEST_F(WindowOcclusionChangeBuilderTest, MultipleChanges) {
+ OcclusionTrackWindowDelegate delegate;
+ auto window = CreateTestWindow(&delegate);
+
+ auto builder = WindowOcclusionChangeBuilder::Create();
+ builder->Add(window.get(), Window::OcclusionState::VISIBLE, SkRegion());
+ builder->Add(window.get(), Window::OcclusionState::HIDDEN, SkRegion());
+
+ SkRegion region;
+ region.setRect(1, 2, 3, 4);
+ builder->Add(window.get(), Window::OcclusionState::OCCLUDED, region);
+
+ // All changes are committed when builder is released.
+ builder.reset();
+
+ EXPECT_EQ(1, delegate.occlusion_change_count());
+ EXPECT_EQ(Window::OcclusionState::OCCLUDED, delegate.last_occlusion_state());
+ EXPECT_EQ(region, delegate.last_occluded_region());
+}
+
+// Test that occlusion info is not updated if window is destroyed before commit.
+TEST_F(WindowOcclusionChangeBuilderTest, DestroyBeforeCommit) {
+ OcclusionTrackWindowDelegate delegate;
+ auto window = CreateTestWindow(&delegate);
+
+ auto builder = WindowOcclusionChangeBuilder::Create();
+ builder->Add(window.get(), Window::OcclusionState::VISIBLE, SkRegion());
+
+ // Destroy window before applying the changes.
+ window.reset();
+
+ // All changes are committed when builder is released.
+ builder.reset();
+
+ // Occlusion info is not updated.
+ EXPECT_EQ(0, delegate.occlusion_change_count());
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/window_occlusion_tracker.cc b/chromium/ui/aura/window_occlusion_tracker.cc
index f7e4fbbb004..1af23f7573a 100644
--- a/chromium/ui/aura/window_occlusion_tracker.cc
+++ b/chromium/ui/aura/window_occlusion_tracker.cc
@@ -11,7 +11,7 @@
#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_occlusion_change_builder.h"
#include "ui/aura/window_tree_host.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "ui/gfx/transform.h"
@@ -126,7 +126,9 @@ void WindowOcclusionTracker::Track(Window* window) {
DCHECK(window != window->GetRootWindow());
auto insert_result = tracked_windows_.insert({window, {}});
- DCHECK(insert_result.second);
+ if (!insert_result.second)
+ return;
+
if (!window_observer_.IsObserving(window))
window_observer_.Add(window);
if (window->GetRootWindow())
@@ -194,31 +196,28 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
++num_times_occlusion_recomputed_;
++num_times_occlusion_recomputed_in_current_step_;
- // 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_)
- tracked_windows_list.Add(tracked_window.first);
-
- while (!tracked_windows_list.windows().empty()) {
- Window* window = tracked_windows_list.Pop();
- auto it = tracked_windows_.find(window);
- if (it != tracked_windows_.end() &&
- 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) {
- if (window->IsVisible()) {
- it->second.occlusion_state = Window::OcclusionState::VISIBLE;
- } else {
- it->second.occlusion_state = Window::OcclusionState::HIDDEN;
- }
- it->second.occluded_region = SkRegion();
+ std::unique_ptr<WindowOcclusionChangeBuilder> change_builder =
+ occlusion_change_builder_factory_
+ ? occlusion_change_builder_factory_.Run()
+ : WindowOcclusionChangeBuilder::Create();
+ for (auto& it : tracked_windows_) {
+ Window* window = it.first;
+ if (it.second.occlusion_state == Window::OcclusionState::UNKNOWN)
+ continue;
+
+ // Fallback to VISIBLE/HIDDEN if the maximum number of times that
+ // occlusion can be recomputed was exceeded.
+ if (exceeded_max_num_times_occlusion_recomputed) {
+ if (window->IsVisible()) {
+ it.second.occlusion_state = Window::OcclusionState::VISIBLE;
+ } else {
+ it.second.occlusion_state = Window::OcclusionState::HIDDEN;
}
-
- window->SetOcclusionInfo(it->second.occlusion_state,
- it->second.occluded_region);
+ it.second.occluded_region = SkRegion();
}
+
+ change_builder->Add(window, it.second.occlusion_state,
+ it.second.occluded_region);
}
}
diff --git a/chromium/ui/aura/window_occlusion_tracker.h b/chromium/ui/aura/window_occlusion_tracker.h
index 6258792f8f0..02e78322c2b 100644
--- a/chromium/ui/aura/window_occlusion_tracker.h
+++ b/chromium/ui/aura/window_occlusion_tracker.h
@@ -33,6 +33,7 @@ class WindowOcclusionTrackerTestApi;
}
class Env;
+class WindowOcclusionChangeBuilder;
// Notifies tracked Windows when their occlusion state change.
//
@@ -73,7 +74,7 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
// 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 {
+ class AURA_EXPORT ScopedExclude : public WindowObserver {
public:
explicit ScopedExclude(Window* window);
~ScopedExclude() override;
@@ -100,6 +101,14 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
window_has_content_callback_ = std::move(callback);
}
+ // Set the factory to create WindowOcclusionChangeBuilder.
+ using OcclusionChangeBuilderFactory =
+ base::RepeatingCallback<std::unique_ptr<WindowOcclusionChangeBuilder>()>;
+ void set_occlusion_change_builder_factory(
+ OcclusionChangeBuilderFactory factory) {
+ occlusion_change_builder_factory_ = std::move(factory);
+ }
+
private:
friend class test::WindowOcclusionTrackerTestApi;
friend class Env;
@@ -269,12 +278,13 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
Window* new_root) override;
void OnWindowLayerRecreated(Window* window) override;
- // 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 occlusion data is tracked.
+ base::flat_map<Window*, OcclusionData> tracked_windows_;
+
// Windows whose bounds or transform are animated.
//
// To reduce the overhead of the WindowOcclusionTracker, windows in this set
@@ -308,6 +318,9 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
// Callback to be invoked for additional window has content check.
WindowHasContentCallback window_has_content_callback_;
+ // Optional factory to create occlusion change builder.
+ OcclusionChangeBuilderFactory occlusion_change_builder_factory_;
+
DISALLOW_COPY_AND_ASSIGN(WindowOcclusionTracker);
};
diff --git a/chromium/ui/aura/window_port.cc b/chromium/ui/aura/window_port.cc
index 80f9c4bcd14..2922baf1a7f 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>* WindowPort::GetObservers(
+base::ReentrantObserverList<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 4c4073afa92..d07c84d6e9a 100644
--- a/chromium/ui/aura/window_port.h
+++ b/chromium/ui/aura/window_port.h
@@ -148,7 +148,8 @@ class AURA_EXPORT WindowPort {
static WindowPort* Get(Window* window);
// Returns the ObserverList of a Window.
- static base::ObserverList<WindowObserver, true>* GetObservers(Window* window);
+ static base::ReentrantObserverList<WindowObserver, true>* GetObservers(
+ Window* window);
private:
const Type type_;
diff --git a/chromium/ui/aura/window_targeter.cc b/chromium/ui/aura/window_targeter.cc
index 14665e38eaf..0e182f2d8e9 100644
--- a/chromium/ui/aura/window_targeter.cc
+++ b/chromium/ui/aura/window_targeter.cc
@@ -29,6 +29,21 @@ bool AreInsetsEmptyOrPositive(const gfx::Insets& insets) {
insets.bottom() >= 0;
}
+void UpdateMusIfNecessary(aura::Window* window,
+ const gfx::Insets& mouse_extend,
+ const gfx::Insets& touch_extend) {
+ if (!window || window->env()->mode() != Env::Mode::MUS)
+ return;
+
+ // Negative insets are used solely to extend the hit-test region of child
+ // windows, which is not needed by code using MUS (negative insets are only
+ // used in the server).
+ if (AreInsetsEmptyOrPositive(mouse_extend) &&
+ AreInsetsEmptyOrPositive(touch_extend)) {
+ WindowPortMus::Get(window)->SetHitTestInsets(mouse_extend, touch_extend);
+ }
+}
+
} // namespace
WindowTargeter::WindowTargeter() {}
@@ -224,6 +239,9 @@ Window* WindowTargeter::FindTargetForKeyEvent(Window* window) {
}
void WindowTargeter::OnInstalled(Window* window) {
+ // Needs to clear the existing insets when uninstalled.
+ if (!window)
+ aura::UpdateMusIfNecessary(window_, gfx::Insets(), gfx::Insets());
window_ = window;
UpdateMusIfNecessary();
}
@@ -334,16 +352,7 @@ bool WindowTargeter::ShouldUseExtendedBounds(const aura::Window* w) const {
// TODO: this function should go away once https://crbug.com/879308 is fixed.
void WindowTargeter::UpdateMusIfNecessary() {
- if (!window_ || window_->env()->mode() != Env::Mode::MUS)
- return;
-
- // Negative insets are used solely to extend the hit-test region of child
- // windows, which is not needed by code using MUS (negative insets are only
- // used in the server).
- if (AreInsetsEmptyOrPositive(mouse_extend_) &&
- AreInsetsEmptyOrPositive(touch_extend_)) {
- WindowPortMus::Get(window_)->SetHitTestInsets(mouse_extend_, touch_extend_);
- }
+ aura::UpdateMusIfNecessary(window_, mouse_extend_, touch_extend_);
}
Window* WindowTargeter::FindTargetForNonKeyEvent(Window* root_window,
diff --git a/chromium/ui/aura/window_tree_host.cc b/chromium/ui/aura/window_tree_host.cc
index 89ed4c6bb9b..08ffa5e729b 100644
--- a/chromium/ui/aura/window_tree_host.cc
+++ b/chromium/ui/aura/window_tree_host.cc
@@ -139,6 +139,10 @@ ui::EventSink* WindowTreeHost::event_sink() {
return dispatcher_.get();
}
+base::WeakPtr<WindowTreeHost> WindowTreeHost::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
gfx::Transform WindowTreeHost::GetRootTransform() const {
gfx::Transform transform;
transform.Scale(device_scale_factor_, device_scale_factor_);
@@ -274,6 +278,10 @@ ui::EventDispatchDetails WindowTreeHost::DispatchKeyEventPostIME(
return dispatch_details;
}
+ui::EventSink* WindowTreeHost::GetEventSink() {
+ return dispatcher_.get();
+}
+
int64_t WindowTreeHost::GetDisplayId() {
return display::Screen::GetScreen()->GetDisplayNearestWindow(window()).id();
}
@@ -379,28 +387,26 @@ void WindowTreeHost::DestroyDispatcher() {
//window()->RemoveOrDestroyChildren();
}
-void WindowTreeHost::CreateCompositor(const viz::FrameSinkId& frame_sink_id,
- bool force_software_compositor,
- bool external_begin_frames_enabled,
- bool are_events_in_pixels,
- const char* trace_environment_name) {
+void WindowTreeHost::CreateCompositor(
+ const viz::FrameSinkId& frame_sink_id,
+ bool force_software_compositor,
+ ui::ExternalBeginFrameClient* external_begin_frame_client,
+ bool are_events_in_pixels,
+ const char* trace_environment_name) {
DCHECK(window()->env());
Env* env = window()->env();
ui::ContextFactory* context_factory = env->context_factory();
DCHECK(context_factory);
ui::ContextFactoryPrivate* context_factory_private =
env->context_factory_private();
- bool enable_surface_synchronization =
- env->mode() == aura::Env::Mode::MUS ||
- features::IsSurfaceSynchronizationEnabled();
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, trace_environment_name);
+ base::ThreadTaskRunnerHandle::Get(), ui::IsPixelCanvasRecordingEnabled(),
+ external_begin_frame_client, force_software_compositor,
+ trace_environment_name);
#if defined(OS_CHROMEOS)
compositor_->AddObserver(this);
#endif
@@ -495,10 +501,6 @@ void WindowTreeHost::OnHostLostWindowCapture() {
capture_window->ReleaseCapture();
}
-ui::EventSink* WindowTreeHost::GetEventSink() {
- return dispatcher_.get();
-}
-
void WindowTreeHost::OnDisplayMetricsChanged(const display::Display& display,
uint32_t metrics) {
if (metrics & DisplayObserver::DISPLAY_METRIC_COLOR_SPACE) {
@@ -546,11 +548,6 @@ void WindowTreeHost::OnCompositingDidCommit(ui::Compositor* compositor) {
base::TimeTicks::Now() - synchronization_start_time_);
}
-void WindowTreeHost::OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) {}
-
-void WindowTreeHost::OnCompositingEnded(ui::Compositor* compositor) {}
-
void WindowTreeHost::OnCompositingChildResizing(ui::Compositor* compositor) {
if (!window()->env()->throttle_input_on_resize() || holding_pointer_moves_)
return;
diff --git a/chromium/ui/aura/window_tree_host.h b/chromium/ui/aura/window_tree_host.h
index e89644f9776..7730ef6a58a 100644
--- a/chromium/ui/aura/window_tree_host.h
+++ b/chromium/ui/aura/window_tree_host.h
@@ -85,6 +85,7 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
Window* window() { return window_; }
const Window* window() const { return window_; }
+ // TODO(msw): Remove this, callers should use GetEventSink().
ui::EventSink* event_sink();
WindowEventDispatcher* dispatcher() {
@@ -95,6 +96,8 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
ui::Compositor* compositor() { return compositor_.get(); }
+ base::WeakPtr<WindowTreeHost> GetWeakPtr();
+
// Gets/Sets the root window's transform.
virtual gfx::Transform GetRootTransform() const;
virtual void SetRootTransform(const gfx::Transform& transform);
@@ -177,6 +180,9 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
ui::KeyEvent* event,
base::OnceCallback<void(bool)> ack_callback) final;
+ // Overridden from ui::EventSource:
+ ui::EventSink* GetEventSink() override;
+
// Returns the id of the display. Default implementation queries Screen.
virtual int64_t GetDisplayId();
@@ -262,7 +268,7 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
void CreateCompositor(
const viz::FrameSinkId& frame_sink_id = viz::FrameSinkId(),
bool force_software_compositor = false,
- bool external_begin_frames_enabled = false,
+ ui::ExternalBeginFrameClient* external_begin_frame_client = nullptr,
bool are_events_in_pixels = true,
const char* trace_environment_name = nullptr);
@@ -298,9 +304,6 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// Hides the WindowTreeHost.
virtual void HideImpl() = 0;
- // Overridden from ui::EventSource:
- ui::EventSink* GetEventSink() override;
-
// display::DisplayObserver implementation.
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t metrics) override;
@@ -333,9 +336,6 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// Overrided from CompositorObserver:
void OnCompositingDidCommit(ui::Compositor* compositor) override;
- void OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) override;
- void OnCompositingEnded(ui::Compositor* compositor) override;
void OnCompositingChildResizing(ui::Compositor* compositor) override;
void OnCompositingShuttingDown(ui::Compositor* compositor) override;
diff --git a/chromium/ui/aura/window_tree_host_platform.cc b/chromium/ui/aura/window_tree_host_platform.cc
index a116ba0b96c..99159327dd4 100644
--- a/chromium/ui/aura/window_tree_host_platform.cc
+++ b/chromium/ui/aura/window_tree_host_platform.cc
@@ -59,7 +59,7 @@ WindowTreeHostPlatform::WindowTreeHostPlatform(
bounds_ = properties.bounds;
CreateCompositor(viz::FrameSinkId(),
/* force_software_compositor */ false,
- /* external_begin_frames_enabled */ false,
+ /* external_begin_frames_enabled */ nullptr,
/* are_events_in_pixels */ true, trace_environment_name);
CreateAndSetPlatformWindow(std::move(properties));
}
diff --git a/chromium/ui/aura/window_unittest.cc b/chromium/ui/aura/window_unittest.cc
index c5cfcd400ac..a7c15069e3f 100644
--- a/chromium/ui/aura/window_unittest.cc
+++ b/chromium/ui/aura/window_unittest.cc
@@ -3255,6 +3255,11 @@ TEST_P(WindowTest, RootWindowUsesCompositorFrameSinkId) {
}
TEST_P(WindowTest, LocalSurfaceIdChanges) {
+ // This uses Window::CreateLayerTreeFrameSink(), which is not wired up in
+ // Mus. At this time it is only used for LOCAL, so it's not wired up for MUS.
+ if (GetParam() == Env::Mode::MUS)
+ return;
+
Window window(nullptr);
window.Init(ui::LAYER_NOT_DRAWN);
window.SetBounds(gfx::Rect(300, 300));
diff --git a/chromium/ui/aura_extra/BUILD.gn b/chromium/ui/aura_extra/BUILD.gn
index 75962dc069c..cd3bf2dc08c 100644
--- a/chromium/ui/aura_extra/BUILD.gn
+++ b/chromium/ui/aura_extra/BUILD.gn
@@ -43,3 +43,36 @@ source_set("vector_resource") {
"//ui/display",
]
}
+
+source_set("window_position_in_root_monitor") {
+ sources = [
+ "window_position_in_root_monitor.cc",
+ "window_position_in_root_monitor.h",
+ ]
+
+ deps = [
+ "//base",
+ "//ui/aura",
+ ]
+}
+
+source_set("tests") {
+ testonly = true
+
+ sources = [
+ "window_occlusion_impl_unittest_win.cc",
+ "window_position_in_root_monitor_unittest.cc",
+ ]
+
+ deps = [
+ ":aura_extra",
+ ":window_position_in_root_monitor",
+ "//base",
+ "//base/test:test_support",
+ "//testing/gtest",
+ "//ui/aura",
+ "//ui/aura:test_support",
+ "//ui/gfx/geometry",
+ "//ui/platform_window",
+ ]
+}
diff --git a/chromium/ui/aura_extra/image_window_delegate.cc b/chromium/ui/aura_extra/image_window_delegate.cc
index 81011c95289..ac8db1057be 100644
--- a/chromium/ui/aura_extra/image_window_delegate.cc
+++ b/chromium/ui/aura_extra/image_window_delegate.cc
@@ -96,7 +96,6 @@ bool ImageWindowDelegate::HasHitTestMask() const {
return false;
}
-void ImageWindowDelegate::GetHitTestMask(gfx::Path* mask) const {
-}
+void ImageWindowDelegate::GetHitTestMask(SkPath* mask) const {}
} // namespace aura_extra
diff --git a/chromium/ui/aura_extra/image_window_delegate.h b/chromium/ui/aura_extra/image_window_delegate.h
index e7db3ebed3a..09c34b23ba5 100644
--- a/chromium/ui/aura_extra/image_window_delegate.h
+++ b/chromium/ui/aura_extra/image_window_delegate.h
@@ -55,7 +55,7 @@ class AURA_EXTRA_EXPORT ImageWindowDelegate : public aura::WindowDelegate {
void OnWindowDestroyed(aura::Window* window) override;
void OnWindowTargetVisibilityChanged(bool visible) override;
bool HasHitTestMask() const override;
- void GetHitTestMask(gfx::Path* mask) const override;
+ void GetHitTestMask(SkPath* mask) const override;
protected:
SkColor background_color_;
diff --git a/chromium/ui/aura_extra/window_position_in_root_monitor.cc b/chromium/ui/aura_extra/window_position_in_root_monitor.cc
new file mode 100644
index 00000000000..1a2919c918b
--- /dev/null
+++ b/chromium/ui/aura_extra/window_position_in_root_monitor.cc
@@ -0,0 +1,71 @@
+// 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/window_position_in_root_monitor.h"
+
+#include "ui/aura/window.h"
+
+namespace aura_extra {
+
+WindowPositionInRootMonitor::WindowPositionInRootMonitor(
+ aura::Window* window,
+ base::RepeatingClosure callback)
+ : callback_(std::move(callback)) {
+ DCHECK(window);
+ AddAncestors(window);
+}
+
+WindowPositionInRootMonitor::~WindowPositionInRootMonitor() {
+ for (aura::Window* ancestor : ancestors_)
+ ancestor->RemoveObserver(this);
+}
+
+void WindowPositionInRootMonitor::AddAncestors(aura::Window* window) {
+ while (window) {
+ ancestors_.push_back(window);
+ window->AddObserver(this);
+ window = window->parent();
+ }
+}
+
+void WindowPositionInRootMonitor::OnWindowDestroyed(aura::Window* window) {
+ // This should only be hit when window has no ancestors (because destroying
+ // a window implicitly removes children).
+ DCHECK_EQ(1u, ancestors_.size());
+ DCHECK_EQ(window, ancestors_[0]);
+ window->RemoveObserver(this);
+ ancestors_.clear();
+}
+
+void WindowPositionInRootMonitor::OnWindowParentChanged(aura::Window* window,
+ aura::Window* parent) {
+ // |window|'s parent is now |parent|. Iterate through the list backwards,
+ // removing windows until |window| is found. Then add all the new ancestors
+ // of |window|.
+ while (!ancestors_.empty()) {
+ if (ancestors_.back() == window) {
+ AddAncestors(parent);
+ // When adding to a root, notify the callback.
+ if (window->GetRootWindow())
+ callback_.Run();
+ return;
+ }
+ ancestors_.back()->RemoveObserver(this);
+ ancestors_.pop_back();
+ }
+ NOTREACHED();
+}
+
+void WindowPositionInRootMonitor::OnWindowBoundsChanged(
+ aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ ui::PropertyChangeReason reason) {
+ if (old_bounds.origin() != new_bounds.origin() &&
+ ancestors_.back()->GetRootWindow()) {
+ callback_.Run();
+ }
+}
+
+} // namespace aura_extra
diff --git a/chromium/ui/aura_extra/window_position_in_root_monitor.h b/chromium/ui/aura_extra/window_position_in_root_monitor.h
new file mode 100644
index 00000000000..3ab44dc0951
--- /dev/null
+++ b/chromium/ui/aura_extra/window_position_in_root_monitor.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_AURA_EXTRA_WINDOW_POSITION_IN_ROOT_MONITOR_H_
+#define UI_AURA_EXTRA_WINDOW_POSITION_IN_ROOT_MONITOR_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "ui/aura/window_observer.h"
+
+namespace aura_extra {
+
+// WindowPositionInRootMonitor notifies a callback any time the position of a
+// window, relative to the root, changes. Changes are only sent when attached
+// to a valid root.
+class WindowPositionInRootMonitor : public aura::WindowObserver {
+ public:
+ WindowPositionInRootMonitor(aura::Window* window,
+ base::RepeatingClosure callback);
+ ~WindowPositionInRootMonitor() override;
+
+ private:
+ // Adds |window| and all its ancestors to |ancestors_|.
+ void AddAncestors(aura::Window* window);
+
+ // aura::WindowObserver:
+ void OnWindowDestroyed(aura::Window* window) override;
+ void OnWindowParentChanged(aura::Window* window,
+ aura::Window* parent) override;
+ void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ ui::PropertyChangeReason reason) override;
+
+ base::RepeatingClosure callback_;
+
+ // The windows being watched. This contains the window supplied to the
+ // constructor and all it's ancestors. This is empty if the window is deleted.
+ std::vector<aura::Window*> ancestors_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowPositionInRootMonitor);
+};
+
+} // namespace aura_extra
+
+#endif // UI_AURA_EXTRA_WINDOW_POSITION_IN_ROOT_MONITOR_H_
diff --git a/chromium/ui/aura_extra/window_position_in_root_monitor_unittest.cc b/chromium/ui/aura_extra/window_position_in_root_monitor_unittest.cc
new file mode 100644
index 00000000000..785e23a35bb
--- /dev/null
+++ b/chromium/ui/aura_extra/window_position_in_root_monitor_unittest.cc
@@ -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.
+
+#include "ui/aura_extra/window_position_in_root_monitor.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/test/bind_test_util.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace aura_extra {
+
+using WindowPositionInRootMonitorTest = aura::test::AuraTestBase;
+
+TEST_F(WindowPositionInRootMonitorTest, Basic) {
+ // Changing the position while not in a root should not notify the callback.
+ std::unique_ptr<aura::Window> w1(
+ aura::test::CreateTestWindowWithId(1, nullptr));
+ w1->set_owned_by_parent(false);
+ bool monitor_notified = false;
+ WindowPositionInRootMonitor monitor(
+ w1.get(), base::BindLambdaForTesting([&] { monitor_notified = true; }));
+ w1->SetBounds(gfx::Rect(1, 2, 3, 4));
+ EXPECT_FALSE(monitor_notified);
+ w1->SetBounds(gfx::Rect(11, 2, 3, 4));
+ EXPECT_FALSE(monitor_notified);
+
+ // Adding an ancestor that is not part of the root should not notify the
+ // callback.
+ std::unique_ptr<aura::Window> w2(
+ aura::test::CreateTestWindowWithId(2, nullptr));
+ w2->set_owned_by_parent(false);
+ w2->AddChild(w1.get());
+ EXPECT_FALSE(monitor_notified);
+ w2->SetBounds(gfx::Rect(21, 10, 20, 20));
+ EXPECT_FALSE(monitor_notified);
+
+ // Adding to the root should immediately notify.
+ root_window()->AddChild(w2.get());
+ EXPECT_TRUE(monitor_notified);
+ monitor_notified = false;
+
+ // Changing |w2|'s bounds show notify as |w2| is the parent and |w1| is in a
+ // root.
+ w2->SetBounds(gfx::Rect(22, 10, 20, 20));
+ EXPECT_TRUE(monitor_notified);
+ monitor_notified = false;
+
+ // Removing an ancestor, and changing the ancestors bounds should not notify.
+ root_window()->RemoveChild(w2.get());
+ EXPECT_FALSE(monitor_notified);
+ w2->SetBounds(gfx::Rect(21, 22, 23, 24));
+ EXPECT_FALSE(monitor_notified);
+
+ // Add |w1| directly to the root, should immediately notify.
+ root_window()->AddChild(w1.get());
+ EXPECT_TRUE(monitor_notified);
+ monitor_notified = false;
+
+ // Changing |w1|s bounds should notify as in a root.
+ w1->SetBounds(gfx::Rect(101, 102, 12, 13));
+ EXPECT_TRUE(monitor_notified);
+ monitor_notified = false;
+
+ // Changing the size should not notify.
+ w1->SetBounds(gfx::Rect(101, 102, 121, 13));
+ EXPECT_FALSE(monitor_notified);
+}
+
+} // namespace aura_extra
diff --git a/chromium/ui/base/BUILD.gn b/chromium/ui/base/BUILD.gn
index 0364813ec74..195435b5cc3 100644
--- a/chromium/ui/base/BUILD.gn
+++ b/chromium/ui/base/BUILD.gn
@@ -10,6 +10,7 @@ import("//build/config/sanitizers/sanitizers.gni")
import("//build/config/ui.gni")
import("//build/util/branding.gni")
import("//testing/test.gni")
+import("//tools/grit/grit_rule.gni")
import("//ui/base/ui_features.gni")
import("//ui/ozone/ozone.gni")
@@ -46,15 +47,11 @@ component("ui_data_pack") {
defines = [ "UI_DATA_PACK_IMPLEMENTATION" ]
- configs += [
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- "//build/config/compiler:no_size_t_to_int_warning",
- "//build/config/compiler:wexit_time_destructors",
- ]
+ configs += [ "//build/config/compiler:wexit_time_destructors" ]
}
-buildflag_header("ui_features") {
- header = "ui_features.h"
+buildflag_header("buildflags") {
+ header = "buildflags.h"
flags = [
"ENABLE_HIDPI=$enable_hidpi",
"ENABLE_MESSAGE_CENTER=$enable_message_center",
@@ -79,18 +76,6 @@ jumbo_component("base") {
"accelerators/platform_accelerator_cocoa.mm",
"class_property.cc",
"class_property.h",
- "clipboard/clipboard_android.cc",
- "clipboard/clipboard_android.h",
- "clipboard/clipboard_mac.h",
- "clipboard/clipboard_mac.mm",
- "clipboard/clipboard_types.h",
- "clipboard/clipboard_util_mac.h",
- "clipboard/clipboard_util_mac.mm",
- "clipboard/clipboard_util_win.cc",
- "clipboard/clipboard_util_win.h",
- "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",
@@ -130,6 +115,8 @@ jumbo_component("base") {
"cocoa/remote_accessibility_api.mm",
"cocoa/remote_layer_api.h",
"cocoa/remote_layer_api.mm",
+ "cocoa/remote_views_window.h",
+ "cocoa/remote_views_window.mm",
"cocoa/secure_password_input.h",
"cocoa/secure_password_input.mm",
"cocoa/text_services_context_menu.cc",
@@ -153,8 +140,6 @@ jumbo_component("base") {
"cursor/cursor.cc",
"cursor/cursor.h",
"cursor/cursor_android.cc",
- "cursor/cursor_data.cc",
- "cursor/cursor_data.h",
"cursor/cursor_loader.h",
"cursor/cursor_type.h",
"cursor/cursor_win.cc",
@@ -209,8 +194,6 @@ jumbo_component("base") {
"models/combobox_model.cc",
"models/combobox_model.h",
"models/combobox_model_observer.h",
- "models/dialog_model.cc",
- "models/dialog_model.h",
"models/list_model.h",
"models/list_model_observer.h",
"models/list_selection_model.cc",
@@ -324,16 +307,6 @@ jumbo_component("base") {
"accelerators/accelerator_manager.h",
"base_window.cc",
"base_window.h",
- "clipboard/clipboard.cc",
- "clipboard/clipboard.h",
- "clipboard/clipboard_constants.cc",
- "clipboard/clipboard_monitor.cc",
- "clipboard/clipboard_monitor.h",
- "clipboard/clipboard_observer.h",
- "clipboard/custom_data_helper.cc",
- "clipboard/custom_data_helper.h",
- "clipboard/scoped_clipboard_writer.cc",
- "clipboard/scoped_clipboard_writer.h",
"cocoa/bubble_closer.h",
"cocoa/bubble_closer.mm",
"cursor/cursor_util.cc",
@@ -347,6 +320,7 @@ jumbo_component("base") {
"emoji/emoji_panel_helper.h",
"idle/idle.cc",
"idle/idle.h",
+ "idle/idle_android.cc",
"idle/idle_chromeos.cc",
"idle/idle_linux.cc",
"idle/idle_mac.mm",
@@ -373,6 +347,12 @@ jumbo_component("base") {
if (is_mac) {
sources += [ "accelerators/media_keys_listener_mac.mm" ]
+ } else if (is_win) {
+ sources += [
+ "accelerators/global_media_keys_listener_win.cc",
+ "accelerators/global_media_keys_listener_win.h",
+ "accelerators/media_keys_listener_win.cc",
+ ]
} else {
sources += [ "accelerators/media_keys_listener_stub.cc" ]
}
@@ -399,17 +379,13 @@ jumbo_component("base") {
]
}
- configs += [
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- "//build/config/compiler:no_size_t_to_int_warning",
- "//build/config/compiler:wexit_time_destructors",
- ]
+ configs += [ "//build/config/compiler:wexit_time_destructors" ]
defines = [ "UI_BASE_IMPLEMENTATION" ]
public_deps = [
+ ":buildflags",
":ui_data_pack",
- ":ui_features",
"//base",
"//skia",
"//ui/gfx",
@@ -422,6 +398,7 @@ jumbo_component("base") {
"//net",
"//third_party/icu",
"//third_party/zlib:zlib",
+ "//ui/base/clipboard:clipboard_types",
"//ui/display",
"//ui/events",
"//ui/events/devices",
@@ -498,11 +475,6 @@ jumbo_component("base") {
if (use_aura) {
deps += [ "//ui/events" ]
sources += [ "window_tracker_template.h" ]
- } else {
- sources -= [
- "cursor/cursor.cc",
- "cursor/cursor.h",
- ]
}
if (!use_aura || !is_linux) {
@@ -523,7 +495,10 @@ jumbo_component("base") {
}
if (is_chromeos) {
- deps += [ "//chromeos" ]
+ deps += [
+ "//chromeos",
+ "//chromeos/dbus",
+ ]
sources -= [ "idle/idle_linux.cc" ]
}
@@ -534,6 +509,10 @@ jumbo_component("base") {
]
}
+ if (is_mac || is_win) {
+ deps += [ "//ui/base/clipboard" ]
+ }
+
libs = []
if (is_win) {
sources += [
@@ -624,7 +603,6 @@ jumbo_component("base") {
"idle/idle.h",
"l10n/l10n_font_util.cc",
"models/button_menu_item_model.cc",
- "models/dialog_model.cc",
"pointer/touch_editing_controller.cc",
"theme_provider.cc",
"ui_base_types.cc",
@@ -632,20 +610,6 @@ jumbo_component("base") {
}
if (use_aura) {
- # Aura clipboard.
- if (use_x11 && is_desktop_linux) {
- sources += [
- "clipboard/clipboard_aurax11.cc",
- "clipboard/clipboard_aurax11.h",
- ]
- } else if (!is_win) {
- # This file is used for all non-X11, non-Windows aura Builds.
- sources += [
- "clipboard/clipboard_aura.cc",
- "clipboard/clipboard_aura.h",
- ]
- }
-
# Cursor
sources += [
"cursor/cursors_aura.cc",
@@ -692,8 +656,6 @@ jumbo_static_library("test_support") {
"test/scoped_fake_nswindow_fullscreen.mm",
"test/scoped_preferred_scroller_style_mac.h",
"test/scoped_preferred_scroller_style_mac.mm",
- "test/test_clipboard.cc",
- "test/test_clipboard.h",
"test/view_tree_validator.h",
"test/view_tree_validator.mm",
"test/windowed_nsnotification_observer.h",
@@ -789,11 +751,62 @@ bundle_data("ui_base_unittests_bundle_data") {
]
}
+# The resource labels below should not end with "_resources" or the Android
+# build rules will look for a nonexistent __build_config label.
+grit("ui_base_test_resources_grit") {
+ testonly = true
+ source = "test/ui_base_test_resources.grd"
+ outputs = [
+ "grit/ui_base_test_resources.h",
+ "ui_base_test_resources.pak",
+ ]
+}
+
+copy("ui_base_test_resources_pak") {
+ testonly = true
+ sources = [
+ "$target_gen_dir/ui_base_test_resources.pak",
+ ]
+ outputs = [
+ "$root_out_dir/ui_base_test_resources.pak",
+ ]
+ public_deps = [
+ ":ui_base_test_resources_grit",
+ ]
+}
+
+if (is_android) {
+ android_assets("ui_base_test_android_assets") {
+ testonly = true
+
+ # Use $target_gen_dir so the associated .pak.info file is available.
+ sources = [
+ "$target_gen_dir/ui_base_test_resources.pak",
+ ]
+ deps = [
+ ":ui_base_test_resources_grit",
+ ]
+ }
+}
+
+if (is_ios) {
+ bundle_data("ui_base_test_bundle_data") {
+ testonly = true
+ public_deps = [
+ ":ui_base_test_resources_grit",
+ ]
+ sources = [
+ "$target_gen_dir/ui_base_test_resources.pak",
+ ]
+ outputs = [
+ "{{bundle_resources_dir}}/{{source_file_part}}",
+ ]
+ }
+}
+
test("ui_base_unittests") {
sources = [
"class_property_unittest.cc",
- "clipboard/clipboard_mac_unittest.mm",
- "clipboard/clipboard_util_mac_unittest.mm",
"l10n/l10n_util_mac_unittest.mm",
"l10n/l10n_util_unittest.cc",
"l10n/time_format_unittest.cc",
@@ -815,7 +828,6 @@ test("ui_base_unittests") {
if (!is_ios) {
sources += [
"test/scoped_fake_nswindow_fullscreen_unittest.mm",
- "test/test_clipboard_unittest.cc",
"test/view_tree_validator_unittest.mm",
]
}
@@ -843,7 +855,6 @@ test("ui_base_unittests") {
"accelerators/menu_label_accelerator_util_linux_unittest.cc",
"accelerators/menu_label_accelerator_util_unittest.cc",
"accelerators/platform_accelerator_cocoa_unittest.mm",
- "clipboard/custom_data_helper_unittest.cc",
"cocoa/base_view_unittest.mm",
"cocoa/bubble_closer_unittest.mm",
"cocoa/cocoa_base_utils_unittest.mm",
@@ -853,10 +864,10 @@ test("ui_base_unittests") {
"cocoa/touch_bar_util_unittest.mm",
"cocoa/tracking_area_unittest.mm",
"cocoa/weak_ptr_nsobject_unittest.mm",
+ "cursor/cursor_util_unittest.cc",
"models/list_model_unittest.cc",
"models/list_selection_model_unittest.cc",
"models/tree_node_model_unittest.cc",
- "test/data/resource.h",
"text/bytes_formatting_unittest.cc",
"webui/web_ui_util_unittest.cc",
]
@@ -889,10 +900,8 @@ test("ui_base_unittests") {
}
}
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
deps = [
+ ":ui_base_test_resources_grit",
":ui_base_unittests_bundle_data",
"//base",
"//base/test:test_support",
@@ -906,6 +915,8 @@ test("ui_base_unittests") {
"//ui/base",
"//ui/base:test_support",
"//ui/base:ui_data_pack",
+ "//ui/base/clipboard:clipboard_test",
+ "//ui/base/clipboard:clipboard_types",
"//ui/display",
"//ui/events:events_base",
"//ui/events:test_support",
@@ -916,6 +927,17 @@ test("ui_base_unittests") {
"//url",
]
+ # Include the correct ui_base_test resources per platform.
+ if (is_android) {
+ deps += [ ":ui_base_test_android_assets" ]
+ data_deps += [ ":ui_base_test_resources_pak" ]
+ } else if (is_ios) {
+ deps += [ ":ui_base_test_bundle_data" ]
+ } else {
+ data += [ "$root_out_dir/ui_base_test_resources.pak" ]
+ data_deps += [ ":ui_base_test_resources_pak" ]
+ }
+
if (build_ime) {
deps += [ "//ui/base/ime" ]
}
@@ -923,7 +945,10 @@ test("ui_base_unittests") {
if (is_ios) {
deps += [ "//ui/resources:ui_test_pak_bundle_data" ]
} else {
- deps += [ "//ui/base/accelerators/mojo:unittests" ]
+ deps += [
+ "//ui/base/accelerators/mojo:unittests",
+ "//ui/base/mojo:unittests",
+ ]
}
if (is_win) {
@@ -961,8 +986,6 @@ test("ui_base_unittests") {
}
if (use_x11) {
- sources += [ "cursor/cursor_loader_x11_unittest.cc" ]
-
configs += [ "//build/config/linux:x11" ]
deps += [
@@ -1056,3 +1079,22 @@ if (is_win) {
]
}
}
+
+# 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("base_interactive_ui_tests") {
+ testonly = true
+ if (is_win) {
+ sources = [
+ "accelerators/global_media_keys_listener_win_interactive_test.cc",
+ ]
+
+ deps = [
+ ":base",
+ ":test_support",
+ "//base/test:test_support",
+ "//testing/gtest",
+ "//ui/events:events",
+ ]
+ }
+}
diff --git a/chromium/ui/base/accelerators/accelerator_manager_unittest.cc b/chromium/ui/base/accelerators/accelerator_manager_unittest.cc
index 4711295de00..76681ea1350 100644
--- a/chromium/ui/base/accelerators/accelerator_manager_unittest.cc
+++ b/chromium/ui/base/accelerators/accelerator_manager_unittest.cc
@@ -4,7 +4,7 @@
#include "ui/base/accelerators/accelerator_manager.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/accelerators/test_accelerator_target.h"
#include "ui/events/event_constants.h"
@@ -26,7 +26,7 @@ const int kAcceleratorModifiers[] = {EF_SHIFT_DOWN, EF_CONTROL_DOWN,
// kAcceleratorModifiers used to determine which flags are set.
int BuildAcceleratorModifier(int id) {
int result = 0;
- for (size_t i = 0; i < arraysize(kAcceleratorModifiers); ++i) {
+ for (size_t i = 0; i < base::size(kAcceleratorModifiers); ++i) {
if (((1 << i) & id) != 0)
result |= kAcceleratorModifiers[i];
}
@@ -124,7 +124,7 @@ TEST_F(AcceleratorManagerTest, Process) {
TestAcceleratorTarget target;
// Test all cases of possible modifiers.
- for (size_t i = 0; i < (1 << arraysize(kAcceleratorModifiers)); ++i) {
+ for (size_t i = 0; i < (1 << base::size(kAcceleratorModifiers)); ++i) {
const int modifiers = BuildAcceleratorModifier(i);
Accelerator accelerator(GetAccelerator(VKEY_A, modifiers));
manager_.Register({accelerator}, AcceleratorManager::kNormalPriority,
@@ -146,7 +146,7 @@ TEST_F(AcceleratorManagerTest, Process) {
EXPECT_FALSE(manager_.Process(GetAccelerator(VKEY_SHIFT, modifiers)))
<< i; // different vkey
- for (size_t test_i = 0; test_i < (1 << arraysize(kAcceleratorModifiers));
+ for (size_t test_i = 0; test_i < (1 << base::size(kAcceleratorModifiers));
++test_i) {
if (test_i == i)
continue;
diff --git a/chromium/ui/base/accelerators/global_media_keys_listener_win.cc b/chromium/ui/base/accelerators/global_media_keys_listener_win.cc
new file mode 100644
index 00000000000..824462adf7e
--- /dev/null
+++ b/chromium/ui/base/accelerators/global_media_keys_listener_win.cc
@@ -0,0 +1,84 @@
+// 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/accelerators/global_media_keys_listener_win.h"
+
+#include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/keycodes/keyboard_code_conversion_win.h"
+#include "ui/gfx/win/singleton_hwnd_hot_key_observer.h"
+
+namespace ui {
+
+// static
+bool GlobalMediaKeysListenerWin::has_instance_ = false;
+
+GlobalMediaKeysListenerWin::GlobalMediaKeysListenerWin(
+ MediaKeysListener::Delegate* delegate)
+ : delegate_(delegate) {
+ DCHECK(delegate_);
+ DCHECK(!has_instance_);
+ has_instance_ = true;
+}
+
+GlobalMediaKeysListenerWin::~GlobalMediaKeysListenerWin() {
+ has_instance_ = false;
+}
+
+bool GlobalMediaKeysListenerWin::StartWatchingMediaKey(KeyboardCode key_code) {
+ DCHECK(IsMediaKeycode(key_code));
+
+ // If the hotkey is already registered, do nothing.
+ if (key_codes_hotkey_observers_.contains(key_code))
+ return true;
+
+ // Create an observer that registers a hot key for |key_code|.
+ std::unique_ptr<gfx::SingletonHwndHotKeyObserver> observer =
+ gfx::SingletonHwndHotKeyObserver::Create(
+ base::BindRepeating(&GlobalMediaKeysListenerWin::OnWndProc,
+ base::Unretained(this)),
+ key_code, /*modifiers=*/0);
+
+ // If observer is null, then the hot key failed to register.
+ bool success = !!observer;
+ if (success)
+ key_codes_hotkey_observers_[key_code] = std::move(observer);
+
+ UMA_HISTOGRAM_BOOLEAN("Media.MediaKeysListener.RegisterHotKeyResult",
+ success);
+
+ return success;
+}
+
+void GlobalMediaKeysListenerWin::StopWatchingMediaKey(KeyboardCode key_code) {
+ DCHECK(IsMediaKeycode(key_code));
+
+ // Deleting the observer automatically unregisters the hot key.
+ key_codes_hotkey_observers_.erase(key_code);
+}
+
+void GlobalMediaKeysListenerWin::OnWndProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ // SingletonHwndHotKeyObservers should only send us hot key messages.
+ DCHECK_EQ(WM_HOTKEY, static_cast<int>(message));
+
+ int win_key_code = HIWORD(lparam);
+ KeyboardCode key_code = KeyboardCodeForWindowsKeyCode(win_key_code);
+
+ // We should only receive hot key events for keys that we're observing.
+ DCHECK(key_codes_hotkey_observers_.contains(key_code));
+
+ int modifiers = 0;
+ modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0;
+ modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0;
+ modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0;
+ Accelerator accelerator(key_code, modifiers);
+
+ delegate_->OnMediaKeysAccelerator(accelerator);
+}
+
+} // namespace ui \ No newline at end of file
diff --git a/chromium/ui/base/accelerators/global_media_keys_listener_win.h b/chromium/ui/base/accelerators/global_media_keys_listener_win.h
new file mode 100644
index 00000000000..4b95a20b1dc
--- /dev/null
+++ b/chromium/ui/base/accelerators/global_media_keys_listener_win.h
@@ -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.
+
+#ifndef UI_BASE_ACCELERATORS_GLOBAL_MEDIA_KEYS_LISTENER_WIN_H_
+#define UI_BASE_ACCELERATORS_GLOBAL_MEDIA_KEYS_LISTENER_WIN_H_
+
+#include "base/containers/flat_map.h"
+#include "base/win/windows_types.h"
+#include "ui/base/accelerators/media_keys_listener.h"
+#include "ui/base/ui_base_export.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+
+namespace gfx {
+
+class SingletonHwndHotKeyObserver;
+
+} // namespace gfx
+
+namespace ui {
+
+// Implementation of MediaKeysListener that uses RegisterHotKey to globally
+// listen for media key presses. It only allows for a single instance to be
+// created in order to prevent conflicts form multiple listeners.
+class UI_BASE_EXPORT GlobalMediaKeysListenerWin : public MediaKeysListener {
+ public:
+ explicit GlobalMediaKeysListenerWin(MediaKeysListener::Delegate* delegate);
+ ~GlobalMediaKeysListenerWin() override;
+
+ static bool has_instance() { return has_instance_; }
+
+ // MediaKeysListener implementation.
+ bool StartWatchingMediaKey(KeyboardCode key_code) override;
+ void StopWatchingMediaKey(KeyboardCode key_code) override;
+
+ private:
+ // Called by SingletonHwndObserver.
+ void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+
+ static bool has_instance_;
+
+ MediaKeysListener::Delegate* delegate_;
+ base::flat_map<KeyboardCode,
+ std::unique_ptr<gfx::SingletonHwndHotKeyObserver>>
+ key_codes_hotkey_observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(GlobalMediaKeysListenerWin);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_ACCELERATORS_GLOBAL_MEDIA_KEYS_LISTENER_WIN_H_
diff --git a/chromium/ui/base/accelerators/global_media_keys_listener_win_interactive_test.cc b/chromium/ui/base/accelerators/global_media_keys_listener_win_interactive_test.cc
new file mode 100644
index 00000000000..c15b5cbb194
--- /dev/null
+++ b/chromium/ui/base/accelerators/global_media_keys_listener_win_interactive_test.cc
@@ -0,0 +1,152 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/accelerators/global_media_keys_listener_win.h"
+
+#include "base/callback.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/event.h"
+
+namespace ui {
+
+namespace {
+
+class MockMediaKeysListenerDelegate : public MediaKeysListener::Delegate {
+ public:
+ MockMediaKeysListenerDelegate() = default;
+ ~MockMediaKeysListenerDelegate() override = default;
+
+ // MediaKeysListener::Delegate implementation.
+ void OnMediaKeysAccelerator(const Accelerator& accelerator) override {
+ received_events_.push_back(accelerator.ToKeyEvent());
+
+ // If we've received the events we're waiting for, stop waiting.
+ if (key_event_wait_loop_ &&
+ received_events_.size() >= num_key_events_to_wait_for_) {
+ key_event_wait_loop_->Quit();
+ }
+ }
+
+ // Loop until we've received |num_events| key events from the listener.
+ void WaitForKeyEvents(uint32_t num_events) {
+ key_event_wait_loop_ = std::make_unique<base::RunLoop>();
+ if (received_events_.size() >= num_events)
+ return;
+
+ num_key_events_to_wait_for_ = num_events;
+ key_event_wait_loop_->Run();
+ }
+
+ // Expect that we have received the correct number of key events.
+ void ExpectReceivedEventsCount(uint32_t count) {
+ EXPECT_EQ(count, received_events_.size());
+ }
+
+ // Expect that the key event received at |index| has the specified key code.
+ void ExpectReceivedEvent(uint32_t index, KeyboardCode code) {
+ ASSERT_LT(index, received_events_.size());
+ KeyEvent* key_event = &received_events_.at(index);
+ EXPECT_EQ(code, key_event->key_code());
+ EXPECT_EQ(ET_KEY_PRESSED, key_event->type());
+ }
+
+ private:
+ std::vector<KeyEvent> received_events_;
+ std::unique_ptr<base::RunLoop> key_event_wait_loop_;
+ uint32_t num_key_events_to_wait_for_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(MockMediaKeysListenerDelegate);
+};
+
+} // anonymous namespace
+
+class GlobalMediaKeysListenerWinInteractiveTest : public testing::Test {
+ public:
+ GlobalMediaKeysListenerWinInteractiveTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
+
+ protected:
+ 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));
+ }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ DWORD time_stamp_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(GlobalMediaKeysListenerWinInteractiveTest);
+};
+
+TEST_F(GlobalMediaKeysListenerWinInteractiveTest, SimplePlayPauseTest) {
+ MockMediaKeysListenerDelegate delegate;
+ GlobalMediaKeysListenerWin listener(&delegate);
+
+ listener.StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+
+ // Send a key press and validate that it was received by the delegate.
+ SendKeyDown(ui::VKEY_MEDIA_PLAY_PAUSE);
+ SendKeyUp(ui::VKEY_MEDIA_PLAY_PAUSE);
+ delegate.WaitForKeyEvents(1);
+ delegate.ExpectReceivedEvent(/*index=*/0, ui::VKEY_MEDIA_PLAY_PAUSE);
+}
+
+TEST_F(GlobalMediaKeysListenerWinInteractiveTest, KeyCanBeReRegistered) {
+ MockMediaKeysListenerDelegate delegate;
+ GlobalMediaKeysListenerWin listener(&delegate);
+
+ // Start listening to register the key.
+ listener.StartWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+ // Stop listening to unregister the key.
+ listener.StopWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+ // Start listening to re-register the key.
+ listener.StartWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+ // Send a key press and validate that it was received by the delegate.
+ SendKeyDown(ui::VKEY_MEDIA_NEXT_TRACK);
+ SendKeyUp(ui::VKEY_MEDIA_NEXT_TRACK);
+ delegate.WaitForKeyEvents(1);
+ delegate.ExpectReceivedEvent(/*index=*/0, ui::VKEY_MEDIA_NEXT_TRACK);
+}
+
+TEST_F(GlobalMediaKeysListenerWinInteractiveTest, ListenForMultipleKeys) {
+ MockMediaKeysListenerDelegate delegate;
+ GlobalMediaKeysListenerWin listener(&delegate);
+
+ listener.StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+ listener.StartWatchingMediaKey(ui::VKEY_MEDIA_STOP);
+
+ // Send a key press and validate that it was received by the delegate.
+ SendKeyDown(ui::VKEY_MEDIA_PLAY_PAUSE);
+ SendKeyUp(ui::VKEY_MEDIA_PLAY_PAUSE);
+ delegate.WaitForKeyEvents(1);
+ delegate.ExpectReceivedEvent(/*index=*/0, ui::VKEY_MEDIA_PLAY_PAUSE);
+
+ // Send a key press and validate that it was received by the delegate.
+ SendKeyDown(ui::VKEY_MEDIA_STOP);
+ SendKeyUp(ui::VKEY_MEDIA_STOP);
+ delegate.WaitForKeyEvents(2);
+ delegate.ExpectReceivedEvent(/*index=*/1, ui::VKEY_MEDIA_STOP);
+}
+
+} // namespace ui \ No newline at end of file
diff --git a/chromium/ui/base/accelerators/media_keys_listener.cc b/chromium/ui/base/accelerators/media_keys_listener.cc
index 4429e44f6af..1145e1f3d79 100644
--- a/chromium/ui/base/accelerators/media_keys_listener.cc
+++ b/chromium/ui/base/accelerators/media_keys_listener.cc
@@ -10,4 +10,10 @@ MediaKeysListener::Delegate::~Delegate() = default;
MediaKeysListener::~MediaKeysListener() = default;
+// static
+bool MediaKeysListener::IsMediaKeycode(KeyboardCode key_code) {
+ return key_code == VKEY_MEDIA_PLAY_PAUSE || key_code == VKEY_MEDIA_STOP ||
+ key_code == VKEY_MEDIA_PREV_TRACK || key_code == VKEY_MEDIA_NEXT_TRACK;
+}
+
} // namespace ui
diff --git a/chromium/ui/base/accelerators/media_keys_listener.h b/chromium/ui/base/accelerators/media_keys_listener.h
index 5ffeafc5511..9072523c656 100644
--- a/chromium/ui/base/accelerators/media_keys_listener.h
+++ b/chromium/ui/base/accelerators/media_keys_listener.h
@@ -8,7 +8,9 @@
#include <memory>
#include "base/callback.h"
+#include "base/observer_list_types.h"
#include "ui/base/ui_base_export.h"
+#include "ui/events/keycodes/keyboard_codes.h"
namespace ui {
@@ -22,22 +24,13 @@ class UI_BASE_EXPORT MediaKeysListener {
kFocused, // Listener only works whan application has focus.
};
- enum class MediaKeysHandleResult {
- kIgnore, // Ignore the key and continue propagation to other system apps.
- kSuppressPropagation, // Handled. Prevent propagation to other system
- // apps.
- };
-
// Media keys accelerators receiver.
- class UI_BASE_EXPORT Delegate {
+ class UI_BASE_EXPORT Delegate : public base::CheckedObserver {
public:
- virtual ~Delegate();
+ ~Delegate() override;
// Called on media key event.
- // Return result - whether event is handled and propagation of event should
- // be suppressed.
- virtual MediaKeysHandleResult OnMediaKeysAccelerator(
- const Accelerator& accelerator) = 0;
+ virtual void OnMediaKeysAccelerator(const Accelerator& accelerator) = 0;
};
// Can return nullptr if media keys listening is not implemented.
@@ -45,14 +38,17 @@ class UI_BASE_EXPORT MediaKeysListener {
static std::unique_ptr<MediaKeysListener> Create(Delegate* delegate,
Scope scope);
+ static bool IsMediaKeycode(KeyboardCode key_code);
+
virtual ~MediaKeysListener();
- // Start receiving media keys events.
- virtual void StartWatchingMediaKeys() = 0;
- // Stop receiving media keys events.
- virtual void StopWatchingMediaKeys() = 0;
- // Whether listener started receiving media keys events.
- virtual bool IsWatchingMediaKeys() const = 0;
+ // Start listening for a given media key. Returns true if the listener
+ // successfully started listening for the key. Some implementations may not be
+ // able to register if another application is already listening to the media
+ // key.
+ virtual bool StartWatchingMediaKey(KeyboardCode key_code) = 0;
+ // Stop listening for a given media key.
+ virtual void StopWatchingMediaKey(KeyboardCode key_code) = 0;
};
} // namespace ui
diff --git a/chromium/ui/base/accelerators/media_keys_listener_mac.mm b/chromium/ui/base/accelerators/media_keys_listener_mac.mm
index cd595b0c017..b48fa8e6386 100644
--- a/chromium/ui/base/accelerators/media_keys_listener_mac.mm
+++ b/chromium/ui/base/accelerators/media_keys_listener_mac.mm
@@ -10,6 +10,7 @@
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hidsystem/ev_keymap.h>
+#include "base/containers/flat_set.h"
#include "ui/base/accelerators/accelerator.h"
namespace ui {
@@ -20,18 +21,18 @@ namespace {
// http://lists.apple.com/archives/cocoa-dev/2007/Aug/msg00499.html
const int kSystemDefinedEventMediaKeysSubtype = 8;
-ui::KeyboardCode MediaKeyCodeToKeyboardCode(int key_code) {
+KeyboardCode MediaKeyCodeToKeyboardCode(int key_code) {
switch (key_code) {
case NX_KEYTYPE_PLAY:
- return ui::VKEY_MEDIA_PLAY_PAUSE;
+ return VKEY_MEDIA_PLAY_PAUSE;
case NX_KEYTYPE_PREVIOUS:
case NX_KEYTYPE_REWIND:
- return ui::VKEY_MEDIA_PREV_TRACK;
+ return VKEY_MEDIA_PREV_TRACK;
case NX_KEYTYPE_NEXT:
case NX_KEYTYPE_FAST:
- return ui::VKEY_MEDIA_NEXT_TRACK;
+ return VKEY_MEDIA_NEXT_TRACK;
}
- return ui::VKEY_UNKNOWN;
+ return VKEY_UNKNOWN;
}
class MediaKeysListenerImpl : public MediaKeysListener {
@@ -41,13 +42,12 @@ class MediaKeysListenerImpl : public MediaKeysListener {
~MediaKeysListenerImpl() override;
// MediaKeysListener:
- void StartWatchingMediaKeys() override;
- void StopWatchingMediaKeys() override;
- bool IsWatchingMediaKeys() const override;
+ bool StartWatchingMediaKey(KeyboardCode key_code) override;
+ void StopWatchingMediaKey(KeyboardCode key_code) override;
private:
// Callback on media key event.
- MediaKeysHandleResult OnMediaKeyEvent(int media_key_code);
+ void OnMediaKeyEvent(KeyboardCode key_code);
// The callback for when an event tap happens.
static CGEventRef EventTapCallback(CGEventTapProxy proxy,
@@ -55,11 +55,16 @@ class MediaKeysListenerImpl : public MediaKeysListener {
CGEventRef event,
void* refcon);
+ // Internal methods to create or remove the event tap.
+ void StartEventTapIfNecessary();
+ void StopEventTapIfNecessary();
+
MediaKeysListener::Delegate* delegate_;
const Scope scope_;
// Event tap for intercepting mac media keys.
CFMachPortRef event_tap_ = nullptr;
CFRunLoopSourceRef event_tap_source_ = nullptr;
+ base::flat_set<KeyboardCode> key_codes_;
DISALLOW_COPY_AND_ASSIGN(MediaKeysListenerImpl);
};
@@ -72,12 +77,23 @@ MediaKeysListenerImpl::MediaKeysListenerImpl(
}
MediaKeysListenerImpl::~MediaKeysListenerImpl() {
- if (event_tap_) {
- StopWatchingMediaKeys();
- }
+ StopEventTapIfNecessary();
+}
+
+bool MediaKeysListenerImpl::StartWatchingMediaKey(KeyboardCode key_code) {
+ key_codes_.insert(key_code);
+ StartEventTapIfNecessary();
+ return true;
+}
+
+void MediaKeysListenerImpl::StopWatchingMediaKey(KeyboardCode key_code) {
+ key_codes_.erase(key_code);
+
+ if (key_codes_.empty())
+ StopEventTapIfNecessary();
}
-void MediaKeysListenerImpl::StartWatchingMediaKeys() {
+void MediaKeysListenerImpl::StartEventTapIfNecessary() {
// Make sure there's no existing event tap.
if (event_tap_) {
return;
@@ -105,7 +121,7 @@ void MediaKeysListenerImpl::StartWatchingMediaKeys() {
kCFRunLoopCommonModes);
}
-void MediaKeysListenerImpl::StopWatchingMediaKeys() {
+void MediaKeysListenerImpl::StopEventTapIfNecessary() {
if (!event_tap_) {
return;
}
@@ -125,15 +141,9 @@ void MediaKeysListenerImpl::StopWatchingMediaKeys() {
event_tap_source_ = nullptr;
}
-bool MediaKeysListenerImpl::IsWatchingMediaKeys() const {
- return event_tap_ != nullptr;
-}
-
-MediaKeysListener::MediaKeysHandleResult MediaKeysListenerImpl::OnMediaKeyEvent(
- int media_key_code) {
- const ui::KeyboardCode key_code = MediaKeyCodeToKeyboardCode(media_key_code);
+void MediaKeysListenerImpl::OnMediaKeyEvent(KeyboardCode key_code) {
// Create an accelerator corresponding to the keyCode.
- const ui::Accelerator accelerator(key_code, 0);
+ const Accelerator accelerator(key_code, 0);
return delegate_->OnMediaKeysAccelerator(accelerator);
}
@@ -191,16 +201,16 @@ CGEventRef MediaKeysListenerImpl::EventTapCallback(CGEventTapProxy proxy,
if (!is_key_pressed)
return event;
- // Now we have a media key that we care about. Send it to the caller.
- auto result = shortcut_listener->OnMediaKeyEvent(key_code);
+ // If we don't care about the given key, ignore this event.
+ const KeyboardCode ui_key_code = MediaKeyCodeToKeyboardCode(key_code);
+ if (!shortcut_listener->key_codes_.contains(ui_key_code))
+ return event;
- // Prevent event from proagating to other apps if handled by Chrome.
- if (result == MediaKeysHandleResult::kSuppressPropagation) {
- return nullptr;
- }
+ // Now we have a media key that we care about. Send it to the caller.
+ shortcut_listener->OnMediaKeyEvent(ui_key_code);
- // By default, pass the event through.
- return event;
+ // Prevent event from proagating to other apps.
+ return nullptr;
}
} // namespace
diff --git a/chromium/ui/base/accelerators/media_keys_listener_win.cc b/chromium/ui/base/accelerators/media_keys_listener_win.cc
new file mode 100644
index 00000000000..5a24b968f38
--- /dev/null
+++ b/chromium/ui/base/accelerators/media_keys_listener_win.cc
@@ -0,0 +1,26 @@
+// 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/accelerators/media_keys_listener.h"
+
+#include "ui/base/accelerators/global_media_keys_listener_win.h"
+
+namespace ui {
+
+std::unique_ptr<MediaKeysListener> MediaKeysListener::Create(
+ MediaKeysListener::Delegate* delegate,
+ MediaKeysListener::Scope scope) {
+ DCHECK(delegate);
+
+ if (scope == Scope::kGlobal) {
+ if (!GlobalMediaKeysListenerWin::has_instance())
+ return std::make_unique<GlobalMediaKeysListenerWin>(delegate);
+ // We shouldn't try to create more than one GlobalMediaKeysListenerWin
+ // instance.
+ NOTREACHED();
+ }
+ return nullptr;
+}
+
+} // namespace ui \ No newline at end of file
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 969b5245b1b..3b9a42f9665 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
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ui {
@@ -24,7 +24,7 @@ TEST(MenuLabelAcceleratorTest, ConvertAcceleratorsFromWindowsStyle) {
{ "&foo &&bar", "_foo &bar" },
{ "&foo &bar", "_foo _bar" },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
std::string result = ConvertAcceleratorsFromWindowsStyle(cases[i].input);
EXPECT_EQ(cases[i].output, result);
}
@@ -43,7 +43,7 @@ TEST(MenuLabelAcceleratorTest, RemoveWindowsStyleAccelerators) {
{ "&foo &&bar", "foo &bar" },
{ "&foo &bar", "foo bar" },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
std::string result = RemoveWindowsStyleAccelerators(cases[i].input);
EXPECT_EQ(cases[i].output, result);
}
diff --git a/chromium/ui/base/accelerators/mojo/BUILD.gn b/chromium/ui/base/accelerators/mojo/BUILD.gn
index 4e028283fc7..afd1aef4383 100644
--- a/chromium/ui/base/accelerators/mojo/BUILD.gn
+++ b/chromium/ui/base/accelerators/mojo/BUILD.gn
@@ -19,7 +19,7 @@ source_set("struct_traits") {
"accelerator_struct_traits.h",
]
public_deps = [
- ":interfaces",
+ ":interfaces_shared_cpp_sources",
"//mojo/public/mojom/base",
"//ui/base",
"//ui/events",
diff --git a/chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h b/chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h
index c0dc969d7fc..b8a75d55bc5 100644
--- a/chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h
+++ b/chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h
@@ -7,7 +7,7 @@
#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/accelerators/mojo/accelerator.mojom.h"
+#include "ui/base/accelerators/mojo/accelerator.mojom-shared.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace mojo {
diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/compiled_resources2.gyp b/chromium/ui/base/accelerators/mojo/typemaps.gni
index 7d419b98824..02a2f7dde8b 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_input/compiled_resources2.gyp
+++ b/chromium/ui/base/accelerators/mojo/typemaps.gni
@@ -1,11 +1,5 @@
# 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.
-{
- 'targets': [
- {
- 'target_name': 'cr_input',
- 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- ],
-}
+
+typemaps = [ "//ui/base/accelerators/mojo/accelerator.typemap" ]
diff --git a/chromium/ui/base/clipboard/BUILD.gn b/chromium/ui/base/clipboard/BUILD.gn
new file mode 100644
index 00000000000..e18f111b594
--- /dev/null
+++ b/chromium/ui/base/clipboard/BUILD.gn
@@ -0,0 +1,165 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/jumbo.gni")
+import("//build/config/ui.gni")
+
+jumbo_component("clipboard_types") {
+ output_name = "ui_base_clipboard_types"
+ sources = [
+ "clipboard_constants.cc",
+ "clipboard_constants.h",
+ "clipboard_constants_mac.mm",
+ "clipboard_format_type_android.cc",
+ "clipboard_format_type_mac.mm",
+ "clipboard_format_type_win.cc",
+ "clipboard_types.h",
+ ]
+
+ if (!is_ios) {
+ if (use_aura) {
+ if ((use_x11 && is_desktop_linux) || !is_win) {
+ sources += [ "clipboard_format_type_aura.cc" ]
+ }
+ }
+
+ sources += [ "clipboard_format_type.h" ]
+ }
+
+ defines = [ "IS_BASE_CLIPBOARD_TYPES_IMPL" ]
+
+ deps = [
+ "//base",
+ ]
+
+ libs = []
+ if (is_mac) {
+ libs += [
+ "AppKit.framework",
+ "CoreFoundation.framework",
+ ]
+ }
+}
+
+jumbo_component("clipboard") {
+ output_name = "ui_base_clipboard"
+
+ sources = [
+ "clipboard.cc",
+ "clipboard.h",
+ "clipboard_android.cc",
+ "clipboard_android.h",
+ "clipboard_mac.h",
+ "clipboard_mac.mm",
+ "clipboard_monitor.cc",
+ "clipboard_monitor.h",
+ "clipboard_observer.h",
+ "clipboard_util_mac.h",
+ "clipboard_util_mac.mm",
+ "clipboard_util_win.cc",
+ "clipboard_util_win.h",
+ "clipboard_win.cc",
+ "clipboard_win.h",
+ "custom_data_helper.cc",
+ "custom_data_helper.h",
+ "scoped_clipboard_writer.cc",
+ "scoped_clipboard_writer.h",
+ ]
+
+ defines = [ "IS_BASE_CLIPBOARD_IMPL" ]
+
+ deps = [
+ "//base",
+ "//net",
+ "//skia",
+ "//ui/events/platform",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ public_deps = [
+ ":clipboard_types",
+ ]
+
+ if (use_aura) {
+ # Aura clipboard.
+ if (use_x11 && is_desktop_linux) {
+ sources += [
+ "clipboard_aurax11.cc",
+ "clipboard_aurax11.h",
+ ]
+ configs += [ "//build/config/linux:x11" ]
+ deps += [
+ "//ui/base",
+ "//ui/base/x",
+ "//ui/gfx/x",
+ ]
+ } else if (!is_win) {
+ # This file is used for all non-X11, non-Windows aura Builds.
+ sources += [
+ "clipboard_aura.cc",
+ "clipboard_aura.h",
+ ]
+ }
+ }
+
+ if (is_android) {
+ deps += [ "//ui/base:ui_base_jni_headers" ]
+ }
+
+ if (is_mac) {
+ deps += [ "//third_party/mozilla" ]
+ libs = [
+ "AppKit.framework",
+ "CoreFoundation.framework",
+ ]
+ }
+}
+
+jumbo_source_set("clipboard_test_support") {
+ testonly = true
+
+ if (!is_ios) {
+ sources = [
+ "test/test_clipboard.cc",
+ "test/test_clipboard.h",
+ ]
+ }
+
+ public_deps = [
+ ":clipboard",
+ "//base",
+ "//skia",
+ ]
+}
+
+source_set("clipboard_test") {
+ testonly = true
+
+ output_name = "ui_base_clipboard_test"
+ sources = [
+ "clipboard_mac_unittest.mm",
+ "clipboard_util_mac_unittest.mm",
+ ]
+
+ if (!is_ios) {
+ sources += [
+ "custom_data_helper_unittest.cc",
+ "test/test_clipboard_unittest.cc",
+ ]
+ }
+
+ deps = [
+ ":clipboard_test_support",
+ "//base/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//ui/events/platform",
+ "//ui/gfx:test_support",
+ ]
+
+ if (is_mac) {
+ deps += [ "//third_party/mozilla" ]
+ }
+}
diff --git a/chromium/ui/base/clipboard/clipboard.cc b/chromium/ui/base/clipboard/clipboard.cc
index a621d64fa9e..26344101061 100644
--- a/chromium/ui/base/clipboard/clipboard.cc
+++ b/chromium/ui/base/clipboard/clipboard.cc
@@ -156,11 +156,9 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) {
}
case CBF_DATA:
- WriteData(
- FormatType::Deserialize(
- std::string(&(params[0].front()), params[0].size())),
- &(params[1].front()),
- params[1].size());
+ WriteData(ClipboardFormatType::Deserialize(
+ std::string(&(params[0].front()), params[0].size())),
+ &(params[1].front()), params[1].size());
break;
default:
diff --git a/chromium/ui/base/clipboard/clipboard.h b/chromium/ui/base/clipboard/clipboard.h
index 60410973f82..913149dbd93 100644
--- a/chromium/ui/base/clipboard/clipboard.h
+++ b/chromium/ui/base/clipboard/clipboard.h
@@ -13,6 +13,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
@@ -24,93 +25,17 @@
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/clipboard_types.h"
-#include "ui/base/ui_base_export.h"
-
-#if defined(OS_WIN)
-#include <objidl.h>
-#endif
class SkBitmap;
-#ifdef __OBJC__
-@class NSString;
-#else
-class NSString;
-#endif
-
namespace ui {
class TestClipboard;
class ScopedClipboardWriter;
-class UI_BASE_EXPORT Clipboard : public base::ThreadChecker {
+class COMPONENT_EXPORT(BASE_CLIPBOARD) Clipboard : public base::ThreadChecker {
public:
- // MIME type constants.
- static const char kMimeTypeText[];
- static const char kMimeTypeURIList[];
- static const char kMimeTypeDownloadURL[];
- static const char kMimeTypeMozillaURL[];
- static const char kMimeTypeHTML[];
- static const char kMimeTypeRTF[];
- static const char kMimeTypePNG[];
- static const char kMimeTypeWebCustomData[];
- static const char kMimeTypeWebkitSmartPaste[];
- static const char kMimeTypePepperCustomData[];
-
- // Platform neutral holder for native data representation of a clipboard type.
- struct UI_BASE_EXPORT FormatType {
- FormatType();
- ~FormatType();
-
- // Serializes and deserializes a FormatType for use in IPC messages.
- std::string Serialize() const;
- static FormatType Deserialize(const std::string& serialization);
-
- // FormatType can be used in a set on some platforms.
- bool operator<(const FormatType& other) const;
-
-#if defined(OS_WIN)
- const FORMATETC& ToFormatEtc() const { return data_; }
-#elif defined(USE_AURA) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
- const std::string& ToString() const { return data_; }
-#elif defined(OS_MACOSX)
- NSString* ToNSString() const { return data_; }
- // Custom copy and assignment constructor to handle NSString.
- FormatType(const FormatType& other);
- FormatType& operator=(const FormatType& other);
-#endif
-
- bool Equals(const FormatType& other) const;
-
- private:
- friend class base::NoDestructor<FormatType>;
- friend class Clipboard;
-
- // Platform-specific glue used internally by the Clipboard class. Each
- // plaform should define,at least one of each of the following:
- // 1. A constructor that wraps that native clipboard format descriptor.
- // 2. An accessor to retrieve the wrapped descriptor.
- // 3. A data member to hold the wrapped descriptor.
- //
- // Note that in some cases, the accessor for the wrapped descriptor may be
- // public, as these format types can be used by drag and drop code as well.
-#if defined(OS_WIN)
- explicit FormatType(UINT native_format);
- FormatType(UINT native_format, LONG index);
- FORMATETC data_;
-#elif defined(USE_AURA) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
- explicit FormatType(const std::string& native_format);
- std::string data_;
-#elif defined(OS_MACOSX)
- explicit FormatType(NSString* native_format);
- NSString* data_;
-#else
-#error No FormatType definition.
-#endif
-
- // Copyable and assignable, since this is essentially an opaque value type.
- };
-
static bool IsSupportedClipboardType(int32_t type) {
switch (type) {
case CLIPBOARD_TYPE_COPY_PASTE:
@@ -166,7 +91,7 @@ class UI_BASE_EXPORT Clipboard : public base::ThreadChecker {
virtual uint64_t GetSequenceNumber(ClipboardType type) const = 0;
// Tests whether the clipboard contains a certain format
- virtual bool IsFormatAvailable(const FormatType& format,
+ virtual bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const = 0;
// Clear the clipboard data.
@@ -208,7 +133,7 @@ class UI_BASE_EXPORT Clipboard : public base::ThreadChecker {
// Reads raw data from the clipboard with the given format type. Stores result
// as a byte vector.
- virtual void ReadData(const FormatType& format,
+ virtual void ReadData(const ClipboardFormatType& format,
std::string* result) const = 0;
// Returns an estimate of the time the clipboard was last updated. If the
@@ -218,38 +143,6 @@ class UI_BASE_EXPORT Clipboard : public base::ThreadChecker {
// Resets the clipboard last modified time to Time::Time().
virtual void ClearLastModifiedTime();
- // Gets the FormatType corresponding to an arbitrary format string,
- // registering it with the system if needed. Due to Windows/Linux
- // limitiations, |format_string| must never be controlled by the user.
- static FormatType GetFormatType(const std::string& format_string);
-
- // Get format identifiers for various types.
- static const FormatType& GetUrlFormatType();
- static const FormatType& GetUrlWFormatType();
- static const FormatType& GetMozUrlFormatType();
- static const FormatType& GetPlainTextFormatType();
- static const FormatType& GetPlainTextWFormatType();
- static const FormatType& GetFilenameFormatType();
- static const FormatType& GetFilenameWFormatType();
- static const FormatType& GetWebKitSmartPasteFormatType();
- // Win: MS HTML Format, Other: Generic HTML format
- static const FormatType& GetHtmlFormatType();
- static const FormatType& GetRtfFormatType();
- static const FormatType& GetBitmapFormatType();
- // TODO(raymes): Unify web custom data and pepper custom data:
- // crbug.com/158399.
- static const FormatType& GetWebCustomDataFormatType();
- static const FormatType& GetPepperCustomDataFormatType();
-
-#if defined(OS_WIN)
- // Firefox text/html
- static const FormatType& GetTextHtmlFormatType();
- static const FormatType& GetCFHDropFormatType();
- static const FormatType& GetFileDescriptorFormatType();
- static const FormatType& GetFileContentZeroFormatType();
- static const FormatType& GetIDListFormatType();
-#endif
-
protected:
static Clipboard* Create();
@@ -258,10 +151,10 @@ class UI_BASE_EXPORT Clipboard : public base::ThreadChecker {
// ObjectType designates the type of data to be stored in the clipboard. This
// designation is shared across all OSes. The system-specific designation
- // is defined by FormatType. A single ObjectType might be represented by
- // several system-specific FormatTypes. For example, on Linux the CBF_TEXT
- // ObjectType maps to "text/plain", "STRING", and several other formats. On
- // windows it maps to CF_UNICODETEXT.
+ // is defined by ClipboardFormatType. A single ObjectType might be represented
+ // by several system-specific ClipboardFormatTypes. For example, on Linux the
+ // CBF_TEXT ObjectType maps to "text/plain", "STRING", and several other
+ // formats. On windows it maps to CF_UNICODETEXT.
//
// The order below is the order in which data will be written to the
// clipboard, so more specific types must be listed before less specific
@@ -326,7 +219,7 @@ class UI_BASE_EXPORT Clipboard : public base::ThreadChecker {
virtual void WriteBitmap(const SkBitmap& bitmap) = 0;
- virtual void WriteData(const FormatType& format,
+ virtual void WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) = 0;
diff --git a/chromium/ui/base/clipboard/clipboard_android.cc b/chromium/ui/base/clipboard/clipboard_android.cc
index 6fe4940555d..40730c16ef9 100644
--- a/chromium/ui/base/clipboard/clipboard_android.cc
+++ b/chromium/ui/base/clipboard/clipboard_android.cc
@@ -18,6 +18,7 @@
#include "base/time/time.h"
#include "jni/Clipboard_jni.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/gfx/geometry/size.h"
// TODO:(andrewhayden) Support additional formats in Android: Bitmap, URI, HTML,
@@ -42,15 +43,6 @@ namespace ui {
namespace {
-// Various formats we support.
-const char kURLFormat[] = "url";
-const char kPlainTextFormat[] = "text";
-const char kHTMLFormat[] = "html";
-const char kRTFFormat[] = "rtf";
-const char kBitmapFormat[] = "bitmap";
-const char kWebKitSmartPasteFormat[] = "webkit_smart";
-const char kBookmarkFormat[] = "bookmark";
-
class ClipboardMap {
public:
ClipboardMap();
@@ -144,22 +136,24 @@ void ClipboardMap::Set(const std::string& format, const std::string& data) {
void ClipboardMap::CommitToAndroidClipboard() {
JNIEnv* env = AttachCurrentThread();
base::AutoLock lock(lock_);
- if (base::ContainsKey(map_, kHTMLFormat)) {
+ if (base::ContainsKey(map_, ClipboardFormatType::GetHtmlType().ToString())) {
// Android's API for storing HTML content on the clipboard requires a plain-
// text representation to be available as well.
- if (!base::ContainsKey(map_, kPlainTextFormat))
+ if (!base::ContainsKey(map_,
+ ClipboardFormatType::GetPlainTextType().ToString()))
return;
- ScopedJavaLocalRef<jstring> html =
- ConvertUTF8ToJavaString(env, map_[kHTMLFormat]);
- ScopedJavaLocalRef<jstring> text =
- ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]);
+ ScopedJavaLocalRef<jstring> html = ConvertUTF8ToJavaString(
+ env, map_[ClipboardFormatType::GetHtmlType().ToString()]);
+ ScopedJavaLocalRef<jstring> text = ConvertUTF8ToJavaString(
+ env, map_[ClipboardFormatType::GetPlainTextType().ToString()]);
DCHECK(html.obj() && text.obj());
Java_Clipboard_setHTMLText(env, clipboard_manager_, html, text);
- } else if (base::ContainsKey(map_, kPlainTextFormat)) {
- ScopedJavaLocalRef<jstring> str =
- ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]);
+ } else if (base::ContainsKey(
+ map_, ClipboardFormatType::GetPlainTextType().ToString())) {
+ ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(
+ env, map_[ClipboardFormatType::GetPlainTextType().ToString()]);
DCHECK(str.obj());
Java_Clipboard_setText(env, clipboard_manager_, str);
} else {
@@ -224,104 +218,17 @@ void ClipboardMap::UpdateFromAndroidClipboard() {
ScopedJavaLocalRef<jstring> jhtml =
Java_Clipboard_getHTMLText(env, clipboard_manager_);
- JNI_Clipboard_AddMapEntry(env, &map_, kPlainTextFormat, jtext);
- JNI_Clipboard_AddMapEntry(env, &map_, kHTMLFormat, jhtml);
+ JNI_Clipboard_AddMapEntry(
+ env, &map_, ClipboardFormatType::GetPlainTextType().ToString().c_str(),
+ jtext);
+ JNI_Clipboard_AddMapEntry(
+ env, &map_, ClipboardFormatType::GetHtmlType().ToString().c_str(), jhtml);
map_state_ = MapState::kUpToDate;
}
} // namespace
-// Clipboard::FormatType implementation.
-Clipboard::FormatType::FormatType() {
-}
-
-Clipboard::FormatType::FormatType(const std::string& native_format)
- : data_(native_format) {
-}
-
-Clipboard::FormatType::~FormatType() {
-}
-
-std::string Clipboard::FormatType::Serialize() const {
- return data_;
-}
-
-// static
-Clipboard::FormatType Clipboard::FormatType::Deserialize(
- const std::string& serialization) {
- return FormatType(serialization);
-}
-
-bool Clipboard::FormatType::operator<(const FormatType& other) const {
- return data_ < other.data_;
-}
-
-bool Clipboard::FormatType::Equals(const FormatType& other) const {
- return data_ == other.data_;
-}
-
-// Various predefined FormatTypes.
-// static
-Clipboard::FormatType Clipboard::GetFormatType(
- const std::string& format_string) {
- return FormatType::Deserialize(format_string);
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
- static base::NoDestructor<FormatType> type(kURLFormat);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
- static base::NoDestructor<FormatType> type(kPlainTextFormat);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
- static base::NoDestructor<FormatType> type(kPlainTextFormat);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
- static base::NoDestructor<FormatType> type(kWebKitSmartPasteFormat);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
- static base::NoDestructor<FormatType> type(kHTMLFormat);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
- static base::NoDestructor<FormatType> type(kRTFFormat);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
- static base::NoDestructor<FormatType> type(kBitmapFormat);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeWebCustomData);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypePepperCustomData);
- return *type;
-}
-
// Clipboard factory method.
// static
Clipboard* Clipboard::Create() {
@@ -360,7 +267,7 @@ uint64_t ClipboardAndroid::GetSequenceNumber(ClipboardType /* type */) const {
return g_map.Get().GetSequenceNumber();
}
-bool ClipboardAndroid::IsFormatAvailable(const Clipboard::FormatType& format,
+bool ClipboardAndroid::IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
@@ -388,16 +295,16 @@ void ClipboardAndroid::ReadAvailableTypes(ClipboardType type,
// would be nice to ask the ClipboardMap to enumerate the types it supports,
// rather than hardcode the list here.
- if (IsFormatAvailable(Clipboard::GetPlainTextFormatType(), type))
+ if (IsFormatAvailable(ClipboardFormatType::GetPlainTextType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypeText));
- if (IsFormatAvailable(Clipboard::GetHtmlFormatType(), type))
+ if (IsFormatAvailable(ClipboardFormatType::GetHtmlType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
// these formats aren't supported by the ClipboardMap currently, but might
// be one day?
- if (IsFormatAvailable(Clipboard::GetRtfFormatType(), type))
+ if (IsFormatAvailable(ClipboardFormatType::GetRtfType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
- if (IsFormatAvailable(Clipboard::GetBitmapFormatType(), type))
+ if (IsFormatAvailable(ClipboardFormatType::GetBitmapType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
*contains_filenames = false;
}
@@ -415,7 +322,7 @@ void ClipboardAndroid::ReadAsciiText(ClipboardType type,
std::string* result) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
- *result = g_map.Get().Get(kPlainTextFormat);
+ *result = g_map.Get().Get(ClipboardFormatType::GetPlainTextType().ToString());
}
// Note: |src_url| isn't really used. It is only implemented in Windows
@@ -429,7 +336,8 @@ void ClipboardAndroid::ReadHTML(ClipboardType type,
if (src_url)
src_url->clear();
- std::string input = g_map.Get().Get(kHTMLFormat);
+ std::string input =
+ g_map.Get().Get(ClipboardFormatType::GetHtmlType().ToString());
*markup = base::UTF8ToUTF16(input);
*fragment_start = 0;
@@ -444,7 +352,8 @@ void ClipboardAndroid::ReadRTF(ClipboardType type, std::string* result) const {
SkBitmap ClipboardAndroid::ReadImage(ClipboardType type) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
- std::string input = g_map.Get().Get(kBitmapFormat);
+ std::string input =
+ g_map.Get().Get(ClipboardFormatType::GetBitmapType().ToString());
SkBitmap bmp;
if (!input.empty()) {
@@ -474,7 +383,7 @@ void ClipboardAndroid::ReadBookmark(base::string16* title,
NOTIMPLEMENTED();
}
-void ClipboardAndroid::ReadData(const Clipboard::FormatType& format,
+void ClipboardAndroid::ReadData(const ClipboardFormatType& format,
std::string* result) const {
DCHECK(CalledOnValidThread());
*result = g_map.Get().Get(format.ToString());
@@ -504,14 +413,16 @@ void ClipboardAndroid::WriteObjects(ClipboardType type,
}
void ClipboardAndroid::WriteText(const char* text_data, size_t text_len) {
- g_map.Get().Set(kPlainTextFormat, std::string(text_data, text_len));
+ g_map.Get().Set(ClipboardFormatType::GetPlainTextType().ToString(),
+ std::string(text_data, text_len));
}
void ClipboardAndroid::WriteHTML(const char* markup_data,
size_t markup_len,
const char* url_data,
size_t url_len) {
- g_map.Get().Set(kHTMLFormat, std::string(markup_data, markup_len));
+ g_map.Get().Set(ClipboardFormatType::GetHtmlType().ToString(),
+ std::string(markup_data, markup_len));
}
void ClipboardAndroid::WriteRTF(const char* rtf_data, size_t data_len) {
@@ -524,13 +435,15 @@ void ClipboardAndroid::WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
size_t url_len) {
- g_map.Get().Set(kBookmarkFormat, std::string(url_data, url_len));
+ g_map.Get().Set(ClipboardFormatType::GetBookmarkType().ToString(),
+ std::string(url_data, url_len));
}
// Write an extra flavor that signifies WebKit was the last to modify the
// pasteboard. This flavor has no data.
void ClipboardAndroid::WriteWebSmartPaste() {
- g_map.Get().Set(kWebKitSmartPasteFormat, std::string());
+ g_map.Get().Set(ClipboardFormatType::GetWebKitSmartPasteType().ToString(),
+ std::string());
}
// Note: we implement this to pass all unit tests but it is currently unclear
@@ -541,10 +454,10 @@ void ClipboardAndroid::WriteBitmap(const SkBitmap& bitmap) {
std::string packed(reinterpret_cast<const char*>(&size), sizeof(size));
packed += std::string(static_cast<const char*>(bitmap.getPixels()),
bitmap.computeByteSize());
- g_map.Get().Set(kBitmapFormat, packed);
+ g_map.Get().Set(ClipboardFormatType::GetBitmapType().ToString(), packed);
}
-void ClipboardAndroid::WriteData(const Clipboard::FormatType& format,
+void ClipboardAndroid::WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) {
g_map.Get().Set(format.ToString(), std::string(data_data, data_len));
diff --git a/chromium/ui/base/clipboard/clipboard_android.h b/chromium/ui/base/clipboard/clipboard_android.h
index 1ef1bee944b..aaa1019777e 100644
--- a/chromium/ui/base/clipboard/clipboard_android.h
+++ b/chromium/ui/base/clipboard/clipboard_android.h
@@ -13,6 +13,7 @@
#include "base/android/scoped_java_ref.h"
#include "base/callback_forward.h"
+#include "base/component_export.h"
#include "base/macros.h"
#include "base/time/time.h"
@@ -30,11 +31,12 @@ class ClipboardAndroid : public Clipboard {
const base::android::JavaParamRef<jobject>& obj);
// Sets the callback called whenever the clipboard is modified.
- UI_BASE_EXPORT void SetModifiedCallback(ModifiedCallback cb);
+ COMPONENT_EXPORT(BASE_CLIPBOARD)
+ void SetModifiedCallback(ModifiedCallback cb);
// Sets the last modified time without calling the above callback.
- UI_BASE_EXPORT void SetLastModifiedTimeWithoutRunningCallback(
- base::Time time);
+ COMPONENT_EXPORT(BASE_CLIPBOARD)
+ void SetLastModifiedTimeWithoutRunningCallback(base::Time time);
private:
friend class Clipboard;
@@ -45,7 +47,7 @@ class ClipboardAndroid : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
uint64_t GetSequenceNumber(ClipboardType type) const override;
- bool IsFormatAvailable(const FormatType& format,
+ bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const override;
void Clear(ClipboardType type) override;
void ReadAvailableTypes(ClipboardType type,
@@ -64,7 +66,8 @@ class ClipboardAndroid : public Clipboard {
const base::string16& type,
base::string16* result) const override;
void ReadBookmark(base::string16* title, std::string* url) const override;
- void ReadData(const FormatType& format, std::string* result) const override;
+ void ReadData(const ClipboardFormatType& format,
+ std::string* result) const override;
base::Time GetLastModifiedTime() const override;
void ClearLastModifiedTime() override;
void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
@@ -80,7 +83,7 @@ class ClipboardAndroid : public Clipboard {
size_t url_len) override;
void WriteWebSmartPaste() override;
void WriteBitmap(const SkBitmap& bitmap) override;
- void WriteData(const FormatType& format,
+ void WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) override;
diff --git a/chromium/ui/base/clipboard/clipboard_aura.cc b/chromium/ui/base/clipboard/clipboard_aura.cc
index 202a1963b0d..653b3ac1f6a 100644
--- a/chromium/ui/base/clipboard/clipboard_aura.cc
+++ b/chromium/ui/base/clipboard/clipboard_aura.cc
@@ -19,6 +19,8 @@
#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_constants.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/gfx/geometry/size.h"
@@ -27,8 +29,6 @@ namespace ui {
namespace {
-const char kMimeTypeFilename[] = "chromium/filename";
-const char kMimeTypeBitmap[] = "image/bmp";
const size_t kMaxClipboardSize = 1;
// Clipboard data format used by AuraClipboard.
@@ -404,117 +404,6 @@ class ClipboardDataBuilder {
ClipboardData* ClipboardDataBuilder::current_data_ = nullptr;
-// Clipboard::FormatType implementation.
-Clipboard::FormatType::FormatType() {
-}
-
-Clipboard::FormatType::FormatType(const std::string& native_format)
- : data_(native_format) {
-}
-
-Clipboard::FormatType::~FormatType() {
-}
-
-std::string Clipboard::FormatType::Serialize() const {
- return data_;
-}
-
-// static
-Clipboard::FormatType Clipboard::FormatType::Deserialize(
- const std::string& serialization) {
- return FormatType(serialization);
-}
-
-bool Clipboard::FormatType::operator<(const FormatType& other) const {
- return data_ < other.data_;
-}
-
-bool Clipboard::FormatType::Equals(const FormatType& other) const {
- return data_ == other.data_;
-}
-
-// Various predefined FormatTypes.
-// static
-Clipboard::FormatType Clipboard::GetFormatType(
- const std::string& format_string) {
- return FormatType::Deserialize(format_string);
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeURIList);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
- return GetUrlFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetMozUrlFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeMozillaURL);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeText);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
- return GetPlainTextFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeFilename);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
- return Clipboard::GetFilenameFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeHTML);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeRTF);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeBitmap);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeWebkitSmartPaste);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeWebCustomData);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypePepperCustomData);
- return *type;
-}
-
// Clipboard factory method.
Clipboard* Clipboard::Create() {
return new ClipboardAura;
@@ -537,20 +426,20 @@ uint64_t ClipboardAura::GetSequenceNumber(ClipboardType type) const {
return clipboard_internal_->sequence_number();
}
-bool ClipboardAura::IsFormatAvailable(const FormatType& format,
+bool ClipboardAura::IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const {
DCHECK(CalledOnValidThread());
DCHECK(IsSupportedClipboardType(type));
- if (GetPlainTextFormatType().Equals(format) ||
- GetUrlFormatType().Equals(format))
+ if (ClipboardFormatType::GetPlainTextType().Equals(format) ||
+ ClipboardFormatType::GetUrlType().Equals(format))
return clipboard_internal_->IsFormatAvailable(TEXT);
- if (GetHtmlFormatType().Equals(format))
+ if (ClipboardFormatType::GetHtmlType().Equals(format))
return clipboard_internal_->IsFormatAvailable(HTML);
- if (GetRtfFormatType().Equals(format))
+ if (ClipboardFormatType::GetRtfType().Equals(format))
return clipboard_internal_->IsFormatAvailable(RTF);
- if (GetBitmapFormatType().Equals(format))
+ if (ClipboardFormatType::GetBitmapType().Equals(format))
return clipboard_internal_->IsFormatAvailable(BITMAP);
- if (GetWebKitSmartPasteFormatType().Equals(format))
+ if (ClipboardFormatType::GetWebKitSmartPasteType().Equals(format))
return clipboard_internal_->IsFormatAvailable(WEB);
const ClipboardData* data = clipboard_internal_->GetData();
return data && data->custom_data_format() == format.ToString();
@@ -573,13 +462,16 @@ void ClipboardAura::ReadAvailableTypes(ClipboardType type,
types->clear();
*contains_filenames = false;
- if (IsFormatAvailable(GetPlainTextFormatType(), type))
- types->push_back(base::UTF8ToUTF16(GetPlainTextFormatType().ToString()));
- if (IsFormatAvailable(GetHtmlFormatType(), type))
- types->push_back(base::UTF8ToUTF16(GetHtmlFormatType().ToString()));
- if (IsFormatAvailable(GetRtfFormatType(), type))
- types->push_back(base::UTF8ToUTF16(GetRtfFormatType().ToString()));
- if (IsFormatAvailable(GetBitmapFormatType(), type))
+ if (IsFormatAvailable(ClipboardFormatType::GetPlainTextType(), type))
+ types->push_back(
+ base::UTF8ToUTF16(ClipboardFormatType::GetPlainTextType().ToString()));
+ if (IsFormatAvailable(ClipboardFormatType::GetHtmlType(), type))
+ types->push_back(
+ base::UTF8ToUTF16(ClipboardFormatType::GetHtmlType().ToString()));
+ if (IsFormatAvailable(ClipboardFormatType::GetRtfType(), type))
+ types->push_back(
+ base::UTF8ToUTF16(ClipboardFormatType::GetRtfType().ToString()));
+ if (IsFormatAvailable(ClipboardFormatType::GetBitmapType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
if (clipboard_internal_->IsFormatAvailable(CUSTOM) &&
@@ -633,7 +525,7 @@ void ClipboardAura::ReadBookmark(base::string16* title,
clipboard_internal_->ReadBookmark(title, url);
}
-void ClipboardAura::ReadData(const FormatType& format,
+void ClipboardAura::ReadData(const ClipboardFormatType& format,
std::string* result) const {
DCHECK(CalledOnValidThread());
clipboard_internal_->ReadData(format.ToString(), result);
@@ -677,7 +569,7 @@ void ClipboardAura::WriteBitmap(const SkBitmap& bitmap) {
ClipboardDataBuilder::WriteBitmap(bitmap);
}
-void ClipboardAura::WriteData(const FormatType& format,
+void ClipboardAura::WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) {
ClipboardDataBuilder::WriteData(format.ToString(), data_data, data_len);
diff --git a/chromium/ui/base/clipboard/clipboard_aura.h b/chromium/ui/base/clipboard/clipboard_aura.h
index 1d3b2083309..16fbfe06905 100644
--- a/chromium/ui/base/clipboard/clipboard_aura.h
+++ b/chromium/ui/base/clipboard/clipboard_aura.h
@@ -24,7 +24,7 @@ class ClipboardAura : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
uint64_t GetSequenceNumber(ClipboardType type) const override;
- bool IsFormatAvailable(const FormatType& format,
+ bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const override;
void Clear(ClipboardType type) override;
void ReadAvailableTypes(ClipboardType type,
@@ -43,7 +43,8 @@ class ClipboardAura : public Clipboard {
const base::string16& type,
base::string16* result) const override;
void ReadBookmark(base::string16* title, std::string* url) const override;
- void ReadData(const FormatType& format, std::string* result) const override;
+ void ReadData(const ClipboardFormatType& format,
+ std::string* result) const override;
void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
void WriteText(const char* text_data, size_t text_len) override;
void WriteHTML(const char* markup_data,
@@ -57,7 +58,7 @@ class ClipboardAura : public Clipboard {
size_t url_len) override;
void WriteWebSmartPaste() override;
void WriteBitmap(const SkBitmap& bitmap) override;
- void WriteData(const FormatType& format,
+ void WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) override;
diff --git a/chromium/ui/base/clipboard/clipboard_aurax11.cc b/chromium/ui/base/clipboard/clipboard_aurax11.cc
index 447beb5bc09..50426b06ebd 100644
--- a/chromium/ui/base/clipboard/clipboard_aurax11.cc
+++ b/chromium/ui/base/clipboard/clipboard_aurax11.cc
@@ -21,6 +21,7 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/x/selection_owner.h"
@@ -42,7 +43,6 @@ namespace {
const char kClipboard[] = "CLIPBOARD";
const char kClipboardManager[] = "CLIPBOARD_MANAGER";
-const char kMimeTypeFilename[] = "chromium/filename";
///////////////////////////////////////////////////////////////////////////////
@@ -135,7 +135,7 @@ class TargetList {
const AtomVector& target_list() { return target_list_; }
bool ContainsText() const;
- bool ContainsFormat(const Clipboard::FormatType& format_type) const;
+ bool ContainsFormat(const ClipboardFormatType& format_type) const;
bool ContainsAtom(::Atom atom) const;
private:
@@ -155,8 +155,7 @@ bool TargetList::ContainsText() const {
return false;
}
-bool TargetList::ContainsFormat(
- const Clipboard::FormatType& format_type) const {
+bool TargetList::ContainsFormat(const ClipboardFormatType& format_type) const {
::Atom atom = gfx::GetAtom(format_type.ToString().c_str());
return ContainsAtom(atom);
}
@@ -169,41 +168,6 @@ bool TargetList::ContainsAtom(::Atom atom) const {
} // namespace
///////////////////////////////////////////////////////////////////////////////
-
-// I would love for the FormatType to really be a wrapper around an X11 ::Atom,
-// but there are a few problems. Chromeos unit tests spawn a new X11 server for
-// each test, so Atom numeric values don't persist across tests. We could still
-// maybe deal with that if we didn't have static accessor methods everywhere.
-
-Clipboard::FormatType::FormatType() {
-}
-
-Clipboard::FormatType::FormatType(const std::string& native_format)
- : data_(native_format) {
-}
-
-Clipboard::FormatType::~FormatType() {
-}
-
-std::string Clipboard::FormatType::Serialize() const {
- return data_;
-}
-
-// static
-Clipboard::FormatType Clipboard::FormatType::Deserialize(
- const std::string& serialization) {
- return FormatType(serialization);
-}
-
-bool Clipboard::FormatType::operator<(const FormatType& other) const {
- return data_ < other.data_;
-}
-
-bool Clipboard::FormatType::Equals(const FormatType& other) const {
- return data_ == other.data_;
-}
-
-///////////////////////////////////////////////////////////////////////////////
// ClipboardAuraX11::AuraX11Details
// Private implementation of our X11 integration. Keeps X11 headers out of the
@@ -259,7 +223,7 @@ class ClipboardAuraX11::AuraX11Details : public PlatformEventDispatcher {
std::vector< ::Atom> GetTextAtoms() const;
// Returns a vector with a |format| converted to an X11 atom.
- std::vector< ::Atom> GetAtomsForFormat(const Clipboard::FormatType& format);
+ std::vector<::Atom> GetAtomsForFormat(const ClipboardFormatType& format);
// Clears a certain clipboard type, whether we own it or not.
void Clear(ClipboardType type);
@@ -448,7 +412,7 @@ std::vector<::Atom> ClipboardAuraX11::AuraX11Details::GetTextAtoms() const {
}
std::vector<::Atom> ClipboardAuraX11::AuraX11Details::GetAtomsForFormat(
- const Clipboard::FormatType& format) {
+ const ClipboardFormatType& format) {
std::vector< ::Atom> atoms;
atoms.push_back(gfx::GetAtom(format.ToString().c_str()));
return atoms;
@@ -541,89 +505,6 @@ uint32_t ClipboardAuraX11::AuraX11Details::DispatchEvent(
}
///////////////////////////////////////////////////////////////////////////////
-// Various predefined FormatTypes.
-// static
-Clipboard::FormatType Clipboard::GetFormatType(
- const std::string& format_string) {
- return FormatType::Deserialize(format_string);
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeURIList);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
- return GetUrlFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetMozUrlFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeMozillaURL);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeText);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
- return GetPlainTextFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeFilename);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
- return Clipboard::GetFilenameFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeHTML);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeRTF);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypePNG);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeWebkitSmartPaste);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypeWebCustomData);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
- static base::NoDestructor<FormatType> type(kMimeTypePepperCustomData);
- return *type;
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Clipboard factory method.
Clipboard* Clipboard::Create() {
return new ClipboardAuraX11;
@@ -653,14 +534,14 @@ uint64_t ClipboardAuraX11::GetSequenceNumber(ClipboardType type) const {
return SelectionChangeObserver::GetInstance()->primary_sequence_number();
}
-bool ClipboardAuraX11::IsFormatAvailable(const FormatType& format,
+bool ClipboardAuraX11::IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const {
DCHECK(CalledOnValidThread());
DCHECK(IsSupportedClipboardType(type));
TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
- if (format.Equals(GetPlainTextFormatType()) ||
- format.Equals(GetUrlFormatType())) {
+ if (format.Equals(ClipboardFormatType::GetPlainTextType()) ||
+ format.Equals(ClipboardFormatType::GetUrlType())) {
return target_list.ContainsText();
}
return target_list.ContainsFormat(format);
@@ -687,16 +568,17 @@ void ClipboardAuraX11::ReadAvailableTypes(ClipboardType type,
if (target_list.ContainsText())
types->push_back(base::UTF8ToUTF16(kMimeTypeText));
- if (target_list.ContainsFormat(GetHtmlFormatType()))
+ if (target_list.ContainsFormat(ClipboardFormatType::GetHtmlType()))
types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
- if (target_list.ContainsFormat(GetRtfFormatType()))
+ if (target_list.ContainsFormat(ClipboardFormatType::GetRtfType()))
types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
- if (target_list.ContainsFormat(GetBitmapFormatType()))
+ if (target_list.ContainsFormat(ClipboardFormatType::GetBitmapType()))
types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
*contains_filenames = false;
SelectionData data(aurax11_details_->RequestAndWaitForTypes(
- type, aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
+ type, aurax11_details_->GetAtomsForFormat(
+ ClipboardFormatType::GetWebCustomDataType())));
if (data.IsValid())
ReadCustomDataTypes(data.GetData(), data.GetSize(), types);
}
@@ -738,7 +620,8 @@ void ClipboardAuraX11::ReadHTML(ClipboardType type,
*fragment_end = 0;
SelectionData data(aurax11_details_->RequestAndWaitForTypes(
- type, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType())));
+ type,
+ aurax11_details_->GetAtomsForFormat(ClipboardFormatType::GetHtmlType())));
if (data.IsValid()) {
*markup = data.GetHtml();
@@ -752,7 +635,8 @@ void ClipboardAuraX11::ReadRTF(ClipboardType type, std::string* result) const {
DCHECK(CalledOnValidThread());
SelectionData data(aurax11_details_->RequestAndWaitForTypes(
- type, aurax11_details_->GetAtomsForFormat(GetRtfFormatType())));
+ type,
+ aurax11_details_->GetAtomsForFormat(ClipboardFormatType::GetRtfType())));
if (data.IsValid())
data.AssignTo(result);
}
@@ -761,7 +645,8 @@ SkBitmap ClipboardAuraX11::ReadImage(ClipboardType type) const {
DCHECK(CalledOnValidThread());
SelectionData data(aurax11_details_->RequestAndWaitForTypes(
- type, aurax11_details_->GetAtomsForFormat(GetBitmapFormatType())));
+ type, aurax11_details_->GetAtomsForFormat(
+ ClipboardFormatType::GetBitmapType())));
if (data.IsValid()) {
SkBitmap bitmap;
if (gfx::PNGCodec::Decode(data.GetData(), data.GetSize(), &bitmap))
@@ -777,8 +662,8 @@ void ClipboardAuraX11::ReadCustomData(ClipboardType clipboard_type,
DCHECK(CalledOnValidThread());
SelectionData data(aurax11_details_->RequestAndWaitForTypes(
- clipboard_type,
- aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
+ clipboard_type, aurax11_details_->GetAtomsForFormat(
+ ClipboardFormatType::GetWebCustomDataType())));
if (data.IsValid())
ReadCustomDataForType(data.GetData(), data.GetSize(), type, result);
}
@@ -790,7 +675,7 @@ void ClipboardAuraX11::ReadBookmark(base::string16* title,
NOTIMPLEMENTED();
}
-void ClipboardAuraX11::ReadData(const FormatType& format,
+void ClipboardAuraX11::ReadData(const ClipboardFormatType& format,
std::string* result) const {
DCHECK(CalledOnValidThread());
@@ -854,7 +739,7 @@ void ClipboardAuraX11::WriteHTML(const char* markup_data,
}
void ClipboardAuraX11::WriteRTF(const char* rtf_data, size_t data_len) {
- WriteData(GetRtfFormatType(), rtf_data, data_len);
+ WriteData(ClipboardFormatType::GetRtfType(), rtf_data, data_len);
}
void ClipboardAuraX11::WriteBookmark(const char* title_data,
@@ -895,12 +780,12 @@ void ClipboardAuraX11::WriteBitmap(const SkBitmap& bitmap) {
}
}
-void ClipboardAuraX11::WriteData(const FormatType& format,
+void ClipboardAuraX11::WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) {
// We assume that certain mapping types are only written by trusted code.
// Therefore we must upkeep their integrity.
- if (format.Equals(GetBitmapFormatType()))
+ if (format.Equals(ClipboardFormatType::GetBitmapType()))
return;
std::vector<unsigned char> bytes(data_data, data_data + data_len);
diff --git a/chromium/ui/base/clipboard/clipboard_aurax11.h b/chromium/ui/base/clipboard/clipboard_aurax11.h
index ba063450504..29d860ca50b 100644
--- a/chromium/ui/base/clipboard/clipboard_aurax11.h
+++ b/chromium/ui/base/clipboard/clipboard_aurax11.h
@@ -25,7 +25,7 @@ class ClipboardAuraX11 : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
uint64_t GetSequenceNumber(ClipboardType type) const override;
- bool IsFormatAvailable(const FormatType& format,
+ bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const override;
void Clear(ClipboardType type) override;
void ReadAvailableTypes(ClipboardType type,
@@ -44,7 +44,8 @@ class ClipboardAuraX11 : public Clipboard {
const base::string16& type,
base::string16* result) const override;
void ReadBookmark(base::string16* title, std::string* url) const override;
- void ReadData(const FormatType& format, std::string* result) const override;
+ void ReadData(const ClipboardFormatType& format,
+ std::string* result) const override;
void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
void WriteText(const char* text_data, size_t text_len) override;
void WriteHTML(const char* markup_data,
@@ -58,7 +59,7 @@ class ClipboardAuraX11 : public Clipboard {
size_t url_len) override;
void WriteWebSmartPaste() override;
void WriteBitmap(const SkBitmap& bitmap) override;
- void WriteData(const FormatType& format,
+ void WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) override;
diff --git a/chromium/ui/base/clipboard/clipboard_constants.cc b/chromium/ui/base/clipboard/clipboard_constants.cc
index 6372353925e..649a78c14fd 100644
--- a/chromium/ui/base/clipboard/clipboard_constants.cc
+++ b/chromium/ui/base/clipboard/clipboard_constants.cc
@@ -2,21 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_constants.h"
namespace ui {
-const char Clipboard::kMimeTypeText[] = "text/plain";
-const char Clipboard::kMimeTypeURIList[] = "text/uri-list";
-const char Clipboard::kMimeTypeMozillaURL[] = "text/x-moz-url";
-const char Clipboard::kMimeTypeDownloadURL[] = "downloadurl";
-const char Clipboard::kMimeTypeHTML[] = "text/html";
-const char Clipboard::kMimeTypeRTF[] = "text/rtf";
-const char Clipboard::kMimeTypePNG[] = "image/png";
+const char kMimeTypeText[] = "text/plain";
+const char kMimeTypeURIList[] = "text/uri-list";
+const char kMimeTypeMozillaURL[] = "text/x-moz-url";
+const char kMimeTypeDownloadURL[] = "downloadurl";
+const char kMimeTypeHTML[] = "text/html";
+const char kMimeTypeRTF[] = "text/rtf";
+const char kMimeTypePNG[] = "image/png";
// TODO(dcheng): This name is temporary. See crbug.com/106449.
-const char Clipboard::kMimeTypeWebCustomData[] = "chromium/x-web-custom-data";
-const char Clipboard::kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
-const char Clipboard::kMimeTypePepperCustomData[] =
- "chromium/x-pepper-custom-data";
+const char kMimeTypeWebCustomData[] = "chromium/x-web-custom-data";
+const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
+const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_constants.h b/chromium/ui/base/clipboard/clipboard_constants.h
new file mode 100644
index 00000000000..8c499112292
--- /dev/null
+++ b/chromium/ui/base/clipboard/clipboard_constants.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_CONSTANTS_H_
+#define UI_BASE_CLIPBOARD_CLIPBOARD_CONSTANTS_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+#endif // defined(OS_MACOSX)
+
+namespace ui {
+
+#if defined(OS_MACOSX) && !defined(USE_AURA)
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES)
+extern NSString* const kWebCustomDataPboardType;
+#endif
+
+// MIME type constants.
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeText[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeURIList[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeDownloadURL[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeMozillaURL[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeHTML[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeRTF[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypePNG[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES)
+extern const char kMimeTypeWebCustomData[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES)
+extern const char kMimeTypeWebkitSmartPaste[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES)
+extern const char kMimeTypePepperCustomData[];
+
+} // namespace ui
+
+#endif // UI_BASE_CLIPBOARD_CLIPBOARD_H_
diff --git a/chromium/ui/base/clipboard/custom_data_helper_mac.mm b/chromium/ui/base/clipboard/clipboard_constants_mac.mm
index 587d7b41a9e..e415c44402e 100644
--- a/chromium/ui/base/clipboard/custom_data_helper_mac.mm
+++ b/chromium/ui/base/clipboard/clipboard_constants_mac.mm
@@ -1,8 +1,8 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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/base/clipboard/custom_data_helper.h"
+#include "ui/base/clipboard/clipboard_constants.h"
#import <Foundation/Foundation.h>
diff --git a/chromium/ui/base/clipboard/clipboard_format_type.h b/chromium/ui/base/clipboard/clipboard_format_type.h
new file mode 100644
index 00000000000..eb5b91ff29f
--- /dev/null
+++ b/chromium/ui/base/clipboard/clipboard_format_type.h
@@ -0,0 +1,118 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_FORMAT_TYPE_H_
+#define UI_BASE_CLIPBOARD_CLIPBOARD_FORMAT_TYPE_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "base/no_destructor.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <objidl.h>
+#endif
+
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+
+namespace ui {
+
+// Platform neutral holder for native data representation of a clipboard type.
+struct COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) ClipboardFormatType {
+ ClipboardFormatType();
+ ~ClipboardFormatType();
+
+ // Serializes and deserializes a ClipboardFormatType for use in IPC messages.
+ std::string Serialize() const;
+ static ClipboardFormatType Deserialize(const std::string& serialization);
+
+ // Gets the ClipboardFormatType corresponding to an arbitrary format string,
+ // registering it with the system if needed. Due to Windows/Linux
+ // limitations, |format_string| must never be controlled by the user.
+ static ClipboardFormatType GetType(const std::string& format_string);
+
+ // Get format identifiers for various types.
+ static const ClipboardFormatType& GetUrlType();
+ static const ClipboardFormatType& GetUrlWType();
+ static const ClipboardFormatType& GetMozUrlType();
+ static const ClipboardFormatType& GetPlainTextType();
+ static const ClipboardFormatType& GetPlainTextWType();
+ static const ClipboardFormatType& GetFilenameType();
+ static const ClipboardFormatType& GetFilenameWType();
+ static const ClipboardFormatType& GetWebKitSmartPasteType();
+ // Win: MS HTML Format, Other: Generic HTML format
+ static const ClipboardFormatType& GetHtmlType();
+ static const ClipboardFormatType& GetRtfType();
+ static const ClipboardFormatType& GetBitmapType();
+ // TODO(raymes): Unify web custom data and pepper custom data:
+ // crbug.com/158399.
+ static const ClipboardFormatType& GetWebCustomDataType();
+ static const ClipboardFormatType& GetPepperCustomDataType();
+
+#if defined(OS_WIN)
+ // Firefox text/html
+ static const ClipboardFormatType& GetTextHtmlType();
+ static const ClipboardFormatType& GetCFHDropType();
+ static const ClipboardFormatType& GetFileDescriptorType();
+ static const ClipboardFormatType& GetFileContentZeroType();
+ static const ClipboardFormatType& GetIDListType();
+#endif
+
+#if defined(OS_ANDROID)
+ static const ClipboardFormatType& GetBookmarkType();
+#endif
+
+ // ClipboardFormatType can be used in a set on some platforms.
+ bool operator<(const ClipboardFormatType& other) const;
+
+#if defined(OS_WIN)
+ const FORMATETC& ToFormatEtc() const { return data_; }
+#elif defined(USE_AURA) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+ const std::string& ToString() const { return data_; }
+#elif defined(OS_MACOSX)
+ NSString* ToNSString() const { return data_; }
+ // Custom copy and assignment constructor to handle NSString.
+ ClipboardFormatType(const ClipboardFormatType& other);
+ ClipboardFormatType& operator=(const ClipboardFormatType& other);
+#endif
+
+ bool Equals(const ClipboardFormatType& other) const;
+
+ private:
+ friend class base::NoDestructor<ClipboardFormatType>;
+ friend struct ClipboardFormatType;
+
+ // Platform-specific glue used internally by the ClipboardFormatType struct.
+ // Each platform should define,at least one of each of the following:
+ // 1. A constructor that wraps that native clipboard format descriptor.
+ // 2. An accessor to retrieve the wrapped descriptor.
+ // 3. A data member to hold the wrapped descriptor.
+ //
+ // Note that in some cases, the accessor for the wrapped descriptor may be
+ // public, as these format types can be used by drag and drop code as well.
+#if defined(OS_WIN)
+ explicit ClipboardFormatType(UINT native_format);
+ ClipboardFormatType(UINT native_format, LONG index);
+ FORMATETC data_;
+#elif defined(USE_AURA) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+ explicit ClipboardFormatType(const std::string& native_format);
+ std::string data_;
+#elif defined(OS_MACOSX)
+ explicit ClipboardFormatType(NSString* native_format);
+ NSString* data_;
+#else
+#error No ClipboardFormatType definition.
+#endif
+
+ // Copyable and assignable, since this is essentially an opaque value type.
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CLIPBOARD_CLIPBOARD_FORMAT_TYPE_H_
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_android.cc b/chromium/ui/base/clipboard/clipboard_format_type_android.cc
new file mode 100644
index 00000000000..74a6e3f4b52
--- /dev/null
+++ b/chromium/ui/base/clipboard/clipboard_format_type_android.cc
@@ -0,0 +1,119 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/clipboard/clipboard_format_type.h"
+
+#include "ui/base/clipboard/clipboard_constants.h"
+
+namespace ui {
+
+namespace {
+
+// Various formats we support.
+const char kURLFormat[] = "url";
+const char kPlainTextFormat[] = "text";
+const char kHTMLFormat[] = "html";
+const char kRTFFormat[] = "rtf";
+const char kBitmapFormat[] = "bitmap";
+const char kWebKitSmartPasteFormat[] = "webkit_smart";
+const char kBookmarkFormat[] = "bookmark";
+
+} // namespace
+
+// ClipboardFormatType implementation.
+ClipboardFormatType::ClipboardFormatType() {}
+
+ClipboardFormatType::ClipboardFormatType(const std::string& native_format)
+ : data_(native_format) {}
+
+ClipboardFormatType::~ClipboardFormatType() {}
+
+std::string ClipboardFormatType::Serialize() const {
+ return data_;
+}
+
+// static
+ClipboardFormatType ClipboardFormatType::Deserialize(
+ const std::string& serialization) {
+ return ClipboardFormatType(serialization);
+}
+
+bool ClipboardFormatType::operator<(const ClipboardFormatType& other) const {
+ return data_ < other.data_;
+}
+
+bool ClipboardFormatType::Equals(const ClipboardFormatType& other) const {
+ return data_ == other.data_;
+}
+
+// Various predefined ClipboardFormatTypes.
+
+// static
+ClipboardFormatType ClipboardFormatType::GetType(
+ const std::string& format_string) {
+ return ClipboardFormatType::Deserialize(format_string);
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlWType() {
+ static base::NoDestructor<ClipboardFormatType> type(kURLFormat);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPlainTextType() {
+ static base::NoDestructor<ClipboardFormatType> type(kPlainTextFormat);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPlainTextWType() {
+ static base::NoDestructor<ClipboardFormatType> type(kPlainTextFormat);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetWebKitSmartPasteType() {
+ static base::NoDestructor<ClipboardFormatType> type(kWebKitSmartPasteFormat);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetHtmlType() {
+ static base::NoDestructor<ClipboardFormatType> type(kHTMLFormat);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetRtfType() {
+ static base::NoDestructor<ClipboardFormatType> type(kRTFFormat);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetBitmapType() {
+ static base::NoDestructor<ClipboardFormatType> type(kBitmapFormat);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetWebCustomDataType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeWebCustomData);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPepperCustomDataType() {
+ static base::NoDestructor<ClipboardFormatType> type(
+ kMimeTypePepperCustomData);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetBookmarkType() {
+ static base::NoDestructor<ClipboardFormatType> type(kBookmarkFormat);
+ return *type;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_aura.cc b/chromium/ui/base/clipboard/clipboard_format_type_aura.cc
new file mode 100644
index 00000000000..e68dacd6571
--- /dev/null
+++ b/chromium/ui/base/clipboard/clipboard_format_type_aura.cc
@@ -0,0 +1,130 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/clipboard/clipboard_format_type.h"
+
+#include "ui/base/clipboard/clipboard_constants.h"
+
+namespace ui {
+
+namespace {
+constexpr char kMimeTypeFilename[] = "chromium/filename";
+}
+
+// I would love for the ClipboardFormatType to really be a wrapper around an X11
+// ::Atom, but there are a few problems. Chromeos unit tests spawn a new X11
+// server for each test, so Atom numeric values don't persist across tests. We
+// could still maybe deal with that if we didn't have static accessor methods
+// everywhere.
+ClipboardFormatType::ClipboardFormatType() = default;
+
+ClipboardFormatType::~ClipboardFormatType() = default;
+
+ClipboardFormatType::ClipboardFormatType(const std::string& native_format)
+ : data_(native_format) {}
+
+std::string ClipboardFormatType::Serialize() const {
+ return data_;
+}
+
+// static
+ClipboardFormatType ClipboardFormatType::Deserialize(
+ const std::string& serialization) {
+ return ClipboardFormatType(serialization);
+}
+
+bool ClipboardFormatType::operator<(const ClipboardFormatType& other) const {
+ return data_ < other.data_;
+}
+
+bool ClipboardFormatType::Equals(const ClipboardFormatType& other) const {
+ return data_ == other.data_;
+}
+
+// Various predefined ClipboardFormatTypes.
+
+// static
+ClipboardFormatType ClipboardFormatType::GetType(
+ const std::string& format_string) {
+ return ClipboardFormatType::Deserialize(format_string);
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeURIList);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlWType() {
+ return ClipboardFormatType::GetUrlType();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetMozUrlType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeMozillaURL);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPlainTextType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeText);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPlainTextWType() {
+ return ClipboardFormatType::GetPlainTextType();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFilenameType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeFilename);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFilenameWType() {
+ return ClipboardFormatType::GetFilenameType();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetHtmlType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeHTML);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetRtfType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeRTF);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetBitmapType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypePNG);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetWebKitSmartPasteType() {
+ static base::NoDestructor<ClipboardFormatType> type(
+ kMimeTypeWebkitSmartPaste);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetWebCustomDataType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeWebCustomData);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPepperCustomDataType() {
+ static base::NoDestructor<ClipboardFormatType> type(
+ kMimeTypePepperCustomData);
+ return *type;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_mac.mm b/chromium/ui/base/clipboard/clipboard_format_type_mac.mm
new file mode 100644
index 00000000000..6ee040c1360
--- /dev/null
+++ b/chromium/ui/base/clipboard/clipboard_format_type_mac.mm
@@ -0,0 +1,144 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/clipboard/clipboard_format_type.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/strings/sys_string_conversions.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+
+namespace ui {
+
+namespace {
+
+// Tells us if WebKit was the last to write to the pasteboard. There's no
+// actual data associated with this type.
+NSString* const kWebSmartPastePboardType = @"NeXT smart paste pasteboard type";
+
+// Pepper custom data format type.
+NSString* const kPepperCustomDataPboardType =
+ @"org.chromium.pepper-custom-data";
+
+} // namespace
+
+// ClipboardFormatType implementation.
+ClipboardFormatType::ClipboardFormatType() : data_(nil) {}
+
+ClipboardFormatType::ClipboardFormatType(NSString* native_format)
+ : data_([native_format retain]) {}
+
+ClipboardFormatType::ClipboardFormatType(const ClipboardFormatType& other)
+ : data_([other.data_ retain]) {}
+
+ClipboardFormatType& ClipboardFormatType::operator=(
+ const ClipboardFormatType& other) {
+ if (this != &other) {
+ [data_ release];
+ data_ = [other.data_ retain];
+ }
+ return *this;
+}
+
+bool ClipboardFormatType::Equals(const ClipboardFormatType& other) const {
+ return [data_ isEqualToString:other.data_];
+}
+
+ClipboardFormatType::~ClipboardFormatType() {
+ [data_ release];
+}
+
+std::string ClipboardFormatType::Serialize() const {
+ return base::SysNSStringToUTF8(data_);
+}
+
+// static
+ClipboardFormatType ClipboardFormatType::Deserialize(
+ const std::string& serialization) {
+ return ClipboardFormatType(base::SysUTF8ToNSString(serialization));
+}
+
+bool ClipboardFormatType::operator<(const ClipboardFormatType& other) const {
+ return [data_ compare:other.data_] == NSOrderedAscending;
+}
+
+// Various predefined ClipboardFormatTypes.
+
+// static
+ClipboardFormatType ClipboardFormatType::GetType(
+ const std::string& format_string) {
+ return ClipboardFormatType::Deserialize(format_string);
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
+ static base::NoDestructor<ClipboardFormatType> type(NSURLPboardType);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlWType() {
+ return ClipboardFormatType::GetUrlType();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPlainTextType() {
+ static base::NoDestructor<ClipboardFormatType> type(NSPasteboardTypeString);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPlainTextWType() {
+ return ClipboardFormatType::GetPlainTextType();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFilenameType() {
+ static base::NoDestructor<ClipboardFormatType> type(NSFilenamesPboardType);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFilenameWType() {
+ return ClipboardFormatType::GetFilenameType();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetHtmlType() {
+ static base::NoDestructor<ClipboardFormatType> type(NSHTMLPboardType);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetRtfType() {
+ static base::NoDestructor<ClipboardFormatType> type(NSRTFPboardType);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetBitmapType() {
+ static base::NoDestructor<ClipboardFormatType> type(NSTIFFPboardType);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetWebKitSmartPasteType() {
+ static base::NoDestructor<ClipboardFormatType> type(kWebSmartPastePboardType);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetWebCustomDataType() {
+ static base::NoDestructor<ClipboardFormatType> type(kWebCustomDataPboardType);
+ return *type;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPepperCustomDataType() {
+ static base::NoDestructor<ClipboardFormatType> type(
+ kPepperCustomDataPboardType);
+ return *type;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_win.cc b/chromium/ui/base/clipboard/clipboard_format_type_win.cc
new file mode 100644
index 00000000000..ebb4ba850bb
--- /dev/null
+++ b/chromium/ui/base/clipboard/clipboard_format_type_win.cc
@@ -0,0 +1,214 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/clipboard/clipboard_format_type.h"
+
+#include <shlobj.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace ui {
+
+// ClipboardFormatType implementation.
+ClipboardFormatType::ClipboardFormatType() : data_() {}
+
+ClipboardFormatType::ClipboardFormatType(UINT native_format) : data_() {
+ // There's no good way to actually initialize this in the constructor in
+ // C++03.
+ data_.cfFormat = static_cast<CLIPFORMAT>(native_format);
+ data_.dwAspect = DVASPECT_CONTENT;
+ data_.lindex = -1;
+ data_.tymed = TYMED_HGLOBAL;
+}
+
+ClipboardFormatType::ClipboardFormatType(UINT native_format, LONG index)
+ : data_() {
+ // There's no good way to actually initialize this in the constructor in
+ // C++03.
+ data_.cfFormat = static_cast<CLIPFORMAT>(native_format);
+ data_.dwAspect = DVASPECT_CONTENT;
+ data_.lindex = index;
+ data_.tymed = TYMED_HGLOBAL;
+}
+
+ClipboardFormatType::~ClipboardFormatType() {}
+
+std::string ClipboardFormatType::Serialize() const {
+ return base::IntToString(data_.cfFormat);
+}
+
+// static
+ClipboardFormatType ClipboardFormatType::Deserialize(
+ const std::string& serialization) {
+ int clipboard_format = -1;
+ if (!base::StringToInt(serialization, &clipboard_format)) {
+ NOTREACHED();
+ return ClipboardFormatType();
+ }
+ return ClipboardFormatType(clipboard_format);
+}
+
+bool ClipboardFormatType::operator<(const ClipboardFormatType& other) const {
+ return data_.cfFormat < other.data_.cfFormat;
+}
+
+bool ClipboardFormatType::Equals(const ClipboardFormatType& other) const {
+ return data_.cfFormat == other.data_.cfFormat;
+}
+
+// Various predefined ClipboardFormatTypes.
+
+// static
+ClipboardFormatType ClipboardFormatType::GetType(
+ const std::string& format_string) {
+ return ClipboardFormatType(
+ ::RegisterClipboardFormat(base::ASCIIToUTF16(format_string).c_str()));
+}
+
+// The following formats can be referenced by ClipboardUtilWin::GetPlainText.
+// For reasons (COM), they must be initialized in a thread-safe manner.
+// TODO(dcheng): We probably need to make static initialization of "known"
+// ClipboardFormatTypes thread-safe on all platforms.
+#define CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(name, ...) \
+ struct ClipboardFormatTypeArgumentForwarder : public ClipboardFormatType { \
+ ClipboardFormatTypeArgumentForwarder() \
+ : ClipboardFormatType(__VA_ARGS__) {} \
+ }; \
+ static base::LazyInstance<ClipboardFormatTypeArgumentForwarder>::Leaky \
+ name = LAZY_INSTANCE_INITIALIZER
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type,
+ ::RegisterClipboardFormat(CFSTR_INETURLA));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlWType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type,
+ ::RegisterClipboardFormat(CFSTR_INETURLW));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetMozUrlType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(L"text/x-moz-url"));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPlainTextType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type, CF_TEXT);
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPlainTextWType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type, CF_UNICODETEXT);
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFilenameType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(CFSTR_FILENAMEA));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFilenameWType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(CFSTR_FILENAMEW));
+ return type.Get();
+}
+
+// MS HTML Format
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetHtmlType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type,
+ ::RegisterClipboardFormat(L"HTML Format"));
+ return type.Get();
+}
+
+// MS RTF Format
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetRtfType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(L"Rich Text Format"));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetBitmapType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type, CF_BITMAP);
+ return type.Get();
+}
+
+// Firefox text/html
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetTextHtmlType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type,
+ ::RegisterClipboardFormat(L"text/html"));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetCFHDropType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type, CF_HDROP);
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFileDescriptorType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFileContentZeroType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0);
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetIDListType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(CFSTR_SHELLIDLIST));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetWebKitSmartPasteType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(L"WebKit Smart Paste Format"));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetWebCustomDataType() {
+ // TODO(dcheng): This name is temporary. See http://crbug.com/106449.
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(L"Chromium Web Custom MIME Data Format"));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetPepperCustomDataType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(L"Chromium Pepper MIME Data Format"));
+ return type.Get();
+}
+#undef CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE
+
+} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_mac.h b/chromium/ui/base/clipboard/clipboard_mac.h
index e902f614ed5..65c377ab7c9 100644
--- a/chromium/ui/base/clipboard/clipboard_mac.h
+++ b/chromium/ui/base/clipboard/clipboard_mac.h
@@ -8,16 +8,16 @@
#include <stddef.h>
#include <stdint.h>
+#include "base/component_export.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/ui_base_export.h"
@class NSPasteboard;
namespace ui {
-class UI_BASE_EXPORT ClipboardMac : public Clipboard {
+class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardMac : public Clipboard {
private:
FRIEND_TEST_ALL_PREFIXES(ClipboardMacTest, ReadImageRetina);
FRIEND_TEST_ALL_PREFIXES(ClipboardMacTest, ReadImageNonRetina);
@@ -31,7 +31,7 @@ class UI_BASE_EXPORT ClipboardMac : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
uint64_t GetSequenceNumber(ClipboardType type) const override;
- bool IsFormatAvailable(const FormatType& format,
+ bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const override;
void Clear(ClipboardType type) override;
void ReadAvailableTypes(ClipboardType type,
@@ -51,7 +51,8 @@ class UI_BASE_EXPORT ClipboardMac : public Clipboard {
const base::string16& type,
base::string16* result) const override;
void ReadBookmark(base::string16* title, std::string* url) const override;
- void ReadData(const FormatType& format, std::string* result) const override;
+ void ReadData(const ClipboardFormatType& format,
+ std::string* result) const override;
void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
void WriteText(const char* text_data, size_t text_len) override;
void WriteHTML(const char* markup_data,
@@ -65,7 +66,7 @@ class UI_BASE_EXPORT ClipboardMac : public Clipboard {
size_t url_len) override;
void WriteWebSmartPaste() override;
void WriteBitmap(const SkBitmap& bitmap) override;
- void WriteData(const FormatType& format,
+ void WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) override;
diff --git a/chromium/ui/base/clipboard/clipboard_mac.mm b/chromium/ui/base/clipboard/clipboard_mac.mm
index 267743860ce..7ec5c99c9ff 100644
--- a/chromium/ui/base/clipboard/clipboard_mac.mm
+++ b/chromium/ui/base/clipboard/clipboard_mac.mm
@@ -11,6 +11,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
@@ -22,6 +23,7 @@
#include "skia/ext/skia_utils_mac.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/clipboard_util_mac.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/gfx/canvas.h"
@@ -32,14 +34,6 @@ namespace ui {
namespace {
-// Tells us if WebKit was the last to write to the pasteboard. There's no
-// actual data associated with this type.
-NSString* const kWebSmartPastePboardType = @"NeXT smart paste pasteboard type";
-
-// Pepper custom data format type.
-NSString* const kPepperCustomDataPboardType =
- @"org.chromium.pepper-custom-data";
-
NSPasteboard* GetPasteboard() {
// The pasteboard can always be nil, since there is a finite amount of storage
// that must be shared between all pasteboards.
@@ -49,125 +43,6 @@ NSPasteboard* GetPasteboard() {
} // namespace
-// Clipboard::FormatType implementation.
-Clipboard::FormatType::FormatType() : data_(nil) {
-}
-
-Clipboard::FormatType::FormatType(NSString* native_format)
- : data_([native_format retain]) {
-}
-
-Clipboard::FormatType::FormatType(const FormatType& other)
- : data_([other.data_ retain]) {
-}
-
-Clipboard::FormatType& Clipboard::FormatType::operator=(
- const FormatType& other) {
- if (this != &other) {
- [data_ release];
- data_ = [other.data_ retain];
- }
- return *this;
-}
-
-bool Clipboard::FormatType::Equals(const FormatType& other) const {
- return [data_ isEqualToString:other.data_];
-}
-
-Clipboard::FormatType::~FormatType() {
- [data_ release];
-}
-
-std::string Clipboard::FormatType::Serialize() const {
- return base::SysNSStringToUTF8(data_);
-}
-
-// static
-Clipboard::FormatType Clipboard::FormatType::Deserialize(
- const std::string& serialization) {
- return FormatType(base::SysUTF8ToNSString(serialization));
-}
-
-bool Clipboard::FormatType::operator<(const FormatType& other) const {
- return [data_ compare:other.data_] == NSOrderedAscending;
-}
-
-// Various predefined FormatTypes.
-// static
-Clipboard::FormatType Clipboard::GetFormatType(
- const std::string& format_string) {
- return FormatType::Deserialize(format_string);
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
- static base::NoDestructor<FormatType> type(NSURLPboardType);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
- return GetUrlFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
- static base::NoDestructor<FormatType> type(NSPasteboardTypeString);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
- return GetPlainTextFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
- static base::NoDestructor<FormatType> type(NSFilenamesPboardType);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
- return GetFilenameFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
- static base::NoDestructor<FormatType> type(NSHTMLPboardType);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
- static base::NoDestructor<FormatType> type(NSRTFPboardType);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
- static base::NoDestructor<FormatType> type(NSTIFFPboardType);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
- static base::NoDestructor<FormatType> type(kWebSmartPastePboardType);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
- static base::NoDestructor<FormatType> type(kWebCustomDataPboardType);
- return *type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
- static base::NoDestructor<FormatType> type(kPepperCustomDataPboardType);
- return *type;
-}
-
// Clipboard factory method.
// static
Clipboard* Clipboard::Create() {
@@ -193,7 +68,7 @@ uint64_t ClipboardMac::GetSequenceNumber(ClipboardType type) const {
return [pb changeCount];
}
-bool ClipboardMac::IsFormatAvailable(const FormatType& format,
+bool ClipboardMac::IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
@@ -223,11 +98,11 @@ void ClipboardMac::ReadAvailableTypes(ClipboardType type,
bool* contains_filenames) const {
DCHECK(CalledOnValidThread());
types->clear();
- if (IsFormatAvailable(Clipboard::GetPlainTextFormatType(), type))
+ if (IsFormatAvailable(ClipboardFormatType::GetPlainTextType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypeText));
- if (IsFormatAvailable(Clipboard::GetHtmlFormatType(), type))
+ if (IsFormatAvailable(ClipboardFormatType::GetHtmlType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
- if (IsFormatAvailable(Clipboard::GetRtfFormatType(), type))
+ if (IsFormatAvailable(ClipboardFormatType::GetRtfType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
NSPasteboard* pb = GetPasteboard();
@@ -299,7 +174,7 @@ void ClipboardMac::ReadRTF(ClipboardType type, std::string* result) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
- return ReadData(GetRtfFormatType(), result);
+ return ReadData(ClipboardFormatType::GetRtfType(), result);
}
SkBitmap ClipboardMac::ReadImage(ClipboardType type, NSPasteboard* pb) const {
@@ -387,7 +262,7 @@ void ClipboardMac::ReadBookmark(base::string16* title, std::string* url) const {
}
}
-void ClipboardMac::ReadData(const FormatType& format,
+void ClipboardMac::ReadData(const ClipboardFormatType& format,
std::string* result) const {
DCHECK(CalledOnValidThread());
NSPasteboard* pb = GetPasteboard();
@@ -433,7 +308,7 @@ void ClipboardMac::WriteHTML(const char* markup_data,
}
void ClipboardMac::WriteRTF(const char* rtf_data, size_t data_len) {
- WriteData(GetRtfFormatType(), rtf_data, data_len);
+ WriteData(ClipboardFormatType::GetRtfType(), rtf_data, data_len);
}
void ClipboardMac::WriteBookmark(const char* title_data,
@@ -475,7 +350,7 @@ void ClipboardMac::WriteBitmap(const SkBitmap& bitmap) {
}
}
-void ClipboardMac::WriteData(const FormatType& format,
+void ClipboardMac::WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) {
NSPasteboard* pb = GetPasteboard();
@@ -488,7 +363,8 @@ void ClipboardMac::WriteData(const FormatType& format,
// pasteboard. This flavor has no data.
void ClipboardMac::WriteWebSmartPaste() {
NSPasteboard* pb = GetPasteboard();
- NSString* format = GetWebKitSmartPasteFormatType().ToNSString();
+ NSString* format =
+ ClipboardFormatType::GetWebKitSmartPasteType().ToNSString();
[pb addTypes:@[ format ] owner:nil];
[pb setData:nil forType:format];
}
diff --git a/chromium/ui/base/clipboard/clipboard_monitor.h b/chromium/ui/base/clipboard/clipboard_monitor.h
index 448c0f76713..bb03186f3d3 100644
--- a/chromium/ui/base/clipboard/clipboard_monitor.h
+++ b/chromium/ui/base/clipboard/clipboard_monitor.h
@@ -5,11 +5,11 @@
#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_MONITOR_H_
#define UI_BASE_CLIPBOARD_CLIPBOARD_MONITOR_H_
+#include "base/component_export.h"
#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
-#include "ui/base/ui_base_export.h"
namespace ui {
@@ -17,7 +17,7 @@ class ClipboardObserver;
// A singleton instance to monitor and notify ClipboardObservers for clipboard
// changes.
-class UI_BASE_EXPORT ClipboardMonitor {
+class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardMonitor {
public:
static ClipboardMonitor* GetInstance();
diff --git a/chromium/ui/base/clipboard/clipboard_observer.h b/chromium/ui/base/clipboard/clipboard_observer.h
index 82afdd38a72..1aa813d63e6 100644
--- a/chromium/ui/base/clipboard/clipboard_observer.h
+++ b/chromium/ui/base/clipboard/clipboard_observer.h
@@ -5,13 +5,13 @@
#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_OBSERVER_H_
#define UI_BASE_CLIPBOARD_CLIPBOARD_OBSERVER_H_
+#include "base/component_export.h"
#include "base/macros.h"
-#include "ui/base/ui_base_export.h"
namespace ui {
// Observer that receives the notifications of clipboard change events.
-class UI_BASE_EXPORT ClipboardObserver {
+class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardObserver {
public:
// Called when clipboard data is changed.
virtual void OnClipboardDataChanged() = 0;
diff --git a/chromium/ui/base/clipboard/clipboard_test_template.h b/chromium/ui/base/clipboard/clipboard_test_template.h
index fd0dcc60cf9..0dde00db8e4 100644
--- a/chromium/ui/base/clipboard/clipboard_test_template.h
+++ b/chromium/ui/base/clipboard/clipboard_test_template.h
@@ -17,6 +17,7 @@
#include <stdint.h>
+#include <array>
#include <memory>
#include <string>
@@ -24,7 +25,6 @@
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -34,8 +34,9 @@
#include "third_party/skia/include/core/SkScalar.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
-#include "ui/base/test/test_clipboard.h"
+#include "ui/base/clipboard/test/test_clipboard.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/half_float.h"
@@ -58,20 +59,22 @@ namespace ui {
template <typename ClipboardTraits>
class ClipboardTest : public PlatformTest {
public:
+ ClipboardTest() {}
+ ~ClipboardTest() override = default;
+
+ // PlatformTest:
+ void SetUp() override {
+ PlatformTest::SetUp();
#if defined(USE_AURA)
- ClipboardTest()
- : scoped_task_environment_(
- base::test::ScopedTaskEnvironment::MainThreadType::UI),
- event_source_(ClipboardTraits::GetEventSource()),
- clipboard_(ClipboardTraits::Create()) {}
-#else
- ClipboardTest()
- : scoped_task_environment_(
- base::test::ScopedTaskEnvironment::MainThreadType::UI),
- clipboard_(ClipboardTraits::Create()) {}
+ event_source_ = ClipboardTraits::GetEventSource();
#endif
+ clipboard_ = ClipboardTraits::Create();
+ }
- ~ClipboardTest() override { ClipboardTraits::Destroy(clipboard_); }
+ void TearDown() override {
+ ClipboardTraits::Destroy(clipboard_);
+ PlatformTest::TearDown();
+ }
protected:
Clipboard& clipboard() { return *clipboard_; }
@@ -84,12 +87,11 @@ class ClipboardTest : public PlatformTest {
}
private:
- base::test::ScopedTaskEnvironment scoped_task_environment_;
#if defined(USE_AURA)
std::unique_ptr<PlatformEventSource> event_source_;
#endif
// ui::Clipboard has a protected destructor, so scoped_ptr doesn't work here.
- Clipboard* const clipboard_;
+ Clipboard* clipboard_ = nullptr;
};
// Hack for tests that need to call static methods of ClipboardTest.
@@ -98,7 +100,9 @@ struct NullClipboardTraits {
static void Destroy(Clipboard*) {}
};
-TYPED_TEST_CASE(ClipboardTest, TypesToTest);
+// |NamesOfTypesToTest| provides a way to differentiate between different
+// clipboard tests that include this file. See docs in gtest-typed-test.h
+TYPED_TEST_CASE(ClipboardTest, TypesToTest, NamesOfTypesToTest);
TYPED_TEST(ClipboardTest, ClearTest) {
{
@@ -109,9 +113,9 @@ TYPED_TEST(ClipboardTest, ClearTest) {
EXPECT_TRUE(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE).empty());
EXPECT_FALSE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextWType(), CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_FALSE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextType(), CLIPBOARD_TYPE_COPY_PASTE));
}
TYPED_TEST(ClipboardTest, TextTest) {
@@ -124,11 +128,11 @@ TYPED_TEST(ClipboardTest, TextTest) {
}
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeText)));
+ Contains(ASCIIToUTF16(kMimeTypeText)));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextWType(), CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextType(), CLIPBOARD_TYPE_COPY_PASTE));
this->clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result);
EXPECT_EQ(text, text_result);
@@ -148,9 +152,9 @@ TYPED_TEST(ClipboardTest, HTMLTest) {
}
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeHTML)));
+ Contains(ASCIIToUTF16(kMimeTypeHTML)));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetHtmlType(), CLIPBOARD_TYPE_COPY_PASTE));
uint32_t fragment_start;
uint32_t fragment_end;
this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result,
@@ -177,9 +181,9 @@ TYPED_TEST(ClipboardTest, RTFTest) {
}
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeRTF)));
- EXPECT_TRUE(this->clipboard().IsFormatAvailable(Clipboard::GetRtfFormatType(),
- CLIPBOARD_TYPE_COPY_PASTE));
+ Contains(ASCIIToUTF16(kMimeTypeRTF)));
+ EXPECT_TRUE(this->clipboard().IsFormatAvailable(
+ ClipboardFormatType::GetRtfType(), CLIPBOARD_TYPE_COPY_PASTE));
std::string result;
this->clipboard().ReadRTF(CLIPBOARD_TYPE_COPY_PASTE, &result);
EXPECT_EQ(rtf, result);
@@ -204,19 +208,19 @@ TYPED_TEST(ClipboardTest, MultipleBufferTest) {
}
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeText)));
+ Contains(ASCIIToUTF16(kMimeTypeText)));
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_SELECTION),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeHTML)));
+ Contains(ASCIIToUTF16(kMimeTypeHTML)));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextType(), CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_FALSE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_SELECTION));
+ ClipboardFormatType::GetPlainTextType(), CLIPBOARD_TYPE_SELECTION));
EXPECT_FALSE(this->clipboard().IsFormatAvailable(
- Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetHtmlType(), CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_SELECTION));
+ ClipboardFormatType::GetHtmlType(), CLIPBOARD_TYPE_SELECTION));
this->clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result);
EXPECT_EQ(text, text_result);
@@ -245,9 +249,9 @@ TYPED_TEST(ClipboardTest, TrickyHTMLTest) {
}
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeHTML)));
+ Contains(ASCIIToUTF16(kMimeTypeHTML)));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetHtmlType(), CLIPBOARD_TYPE_COPY_PASTE));
uint32_t fragment_start;
uint32_t fragment_end;
this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result,
@@ -275,9 +279,9 @@ TYPED_TEST(ClipboardTest, UnicodeHTMLTest) {
}
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeHTML)));
+ Contains(ASCIIToUTF16(kMimeTypeHTML)));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetHtmlType(), CLIPBOARD_TYPE_COPY_PASTE));
uint32_t fragment_start;
uint32_t fragment_end;
this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result,
@@ -302,7 +306,7 @@ TYPED_TEST(ClipboardTest, BookmarkTest) {
}
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetUrlWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetUrlWType(), CLIPBOARD_TYPE_COPY_PASTE));
this->clipboard().ReadBookmark(&title_result, &url_result);
EXPECT_EQ(title, title_result);
EXPECT_EQ(url, url_result);
@@ -322,15 +326,15 @@ TYPED_TEST(ClipboardTest, MultiFormatTest) {
}
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeHTML)));
+ Contains(ASCIIToUTF16(kMimeTypeHTML)));
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeText)));
+ Contains(ASCIIToUTF16(kMimeTypeText)));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetHtmlType(), CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextWType(), CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextType(), CLIPBOARD_TYPE_COPY_PASTE));
uint32_t fragment_start;
uint32_t fragment_end;
this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result,
@@ -358,11 +362,11 @@ TYPED_TEST(ClipboardTest, URLTest) {
}
EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
- Contains(ASCIIToUTF16(Clipboard::kMimeTypeText)));
+ Contains(ASCIIToUTF16(kMimeTypeText)));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextWType(), CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetPlainTextType(), CLIPBOARD_TYPE_COPY_PASTE));
base::string16 text_result;
this->clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result);
@@ -399,7 +403,7 @@ static void TestBitmapWrite(Clipboard* clipboard,
scw.WriteImage(bitmap);
}
- EXPECT_TRUE(clipboard->IsFormatAvailable(Clipboard::GetBitmapFormatType(),
+ EXPECT_TRUE(clipboard->IsFormatAvailable(ClipboardFormatType::GetBitmapType(),
CLIPBOARD_TYPE_COPY_PASTE));
const SkBitmap& image = clipboard->ReadImage(CLIPBOARD_TYPE_COPY_PASTE);
ASSERT_EQ(image.info().colorType(), kN32_SkColorType);
@@ -517,8 +521,8 @@ TYPED_TEST(ClipboardTest, Bitmap_N32_Premul_2x7) {
} // namespace
TYPED_TEST(ClipboardTest, DataTest) {
- const ui::Clipboard::FormatType kFormat =
- ui::Clipboard::GetFormatType("chromium/x-test-format");
+ const ui::ClipboardFormatType kFormat =
+ ui::ClipboardFormatType::GetType("chromium/x-test-format");
std::string payload("test string");
base::Pickle write_pickle;
write_pickle.WriteString(payload);
@@ -542,14 +546,14 @@ TYPED_TEST(ClipboardTest, DataTest) {
}
TYPED_TEST(ClipboardTest, MultipleDataTest) {
- const ui::Clipboard::FormatType kFormat1 =
- ui::Clipboard::GetFormatType("chromium/x-test-format1");
+ const ui::ClipboardFormatType kFormat1 =
+ ui::ClipboardFormatType::GetType("chromium/x-test-format1");
std::string payload1("test string1");
base::Pickle write_pickle1;
write_pickle1.WriteString(payload1);
- const ui::Clipboard::FormatType kFormat2 =
- ui::Clipboard::GetFormatType("chromium/x-test-format2");
+ const ui::ClipboardFormatType kFormat2 =
+ ui::ClipboardFormatType::GetType("chromium/x-test-format2");
std::string payload2("test string2");
base::Pickle write_pickle2;
write_pickle2.WriteString(payload2);
@@ -613,7 +617,7 @@ TYPED_TEST(ClipboardTest, HyperlinkTest) {
}
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetHtmlType(), CLIPBOARD_TYPE_COPY_PASTE));
uint32_t fragment_start;
uint32_t fragment_end;
this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &html_result,
@@ -631,7 +635,8 @@ TYPED_TEST(ClipboardTest, WebSmartPasteTest) {
}
EXPECT_TRUE(this->clipboard().IsFormatAvailable(
- Clipboard::GetWebKitSmartPasteFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
+ ClipboardFormatType::GetWebKitSmartPasteType(),
+ CLIPBOARD_TYPE_COPY_PASTE));
}
#if defined(OS_WIN) // Windows only tests.
@@ -752,7 +757,7 @@ TYPED_TEST(ClipboardTest, WriteHyperlinkEmptyParams) {
TYPED_TEST(ClipboardTest, WritePickledData) {
ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
- scw.WritePickledData(base::Pickle(), Clipboard::GetPlainTextFormatType());
+ scw.WritePickledData(base::Pickle(), ClipboardFormatType::GetPlainTextType());
}
TYPED_TEST(ClipboardTest, WriteImageEmptyParams) {
@@ -762,4 +767,4 @@ TYPED_TEST(ClipboardTest, WriteImageEmptyParams) {
} // namespace ui
-#endif // UI_BASE_CLIPBOARD_CLIPBOARD_TEST_TEMPLATE_H_ \ No newline at end of file
+#endif // UI_BASE_CLIPBOARD_CLIPBOARD_TEST_TEMPLATE_H_
diff --git a/chromium/ui/base/clipboard/clipboard_unittest.cc b/chromium/ui/base/clipboard/clipboard_unittest.cc
index 08b2c175ffb..3c6eb93dd6b 100644
--- a/chromium/ui/base/clipboard/clipboard_unittest.cc
+++ b/chromium/ui/base/clipboard/clipboard_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/base/clipboard/clipboard.h"
+#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(USE_AURA)
@@ -12,6 +13,12 @@
namespace ui {
+namespace {
+
+base::test::ScopedTaskEnvironment* g_task_environment = nullptr;
+
+} // namespace
+
struct PlatformClipboardTraits {
#if defined(USE_AURA)
static std::unique_ptr<PlatformEventSource> GetEventSource() {
@@ -19,15 +26,31 @@ struct PlatformClipboardTraits {
}
#endif
- static Clipboard* Create() { return Clipboard::GetForCurrentThread(); }
+ static Clipboard* Create() {
+ DCHECK(!g_task_environment);
+ g_task_environment = new base::test::ScopedTaskEnvironment(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI);
+ return Clipboard::GetForCurrentThread();
+ }
static void Destroy(Clipboard* clipboard) {
ASSERT_EQ(Clipboard::GetForCurrentThread(), clipboard);
Clipboard::DestroyClipboardForCurrentThread();
+ delete g_task_environment;
+ g_task_environment = nullptr;
+ }
+};
+
+class BaseClipboardTestName {
+ public:
+ template <typename T>
+ static std::string GetName(int index) {
+ return "BaseClipboardTest";
}
};
-typedef PlatformClipboardTraits TypesToTest;
+using TypesToTest = PlatformClipboardTraits;
+using NamesOfTypesToTest = BaseClipboardTestName;
} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_util_mac.h b/chromium/ui/base/clipboard/clipboard_util_mac.h
index 29f927c3f31..d230ba82928 100644
--- a/chromium/ui/base/clipboard/clipboard_util_mac.h
+++ b/chromium/ui/base/clipboard/clipboard_util_mac.h
@@ -7,18 +7,18 @@
#import <AppKit/AppKit.h>
+#include "base/component_export.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/ref_counted.h"
#include "ui/base/clipboard/clipboard_types.h"
-#include "ui/base/ui_base_export.h"
namespace ui {
// A publicly-used UTI for the name of a URL. It really should be in a system
// header but isn't.
-UI_BASE_EXPORT extern NSString* const kUTTypeURLName;
+COMPONENT_EXPORT(BASE_CLIPBOARD) extern NSString* const kUTTypeURLName;
-class UI_BASE_EXPORT UniquePasteboard
+class COMPONENT_EXPORT(BASE_CLIPBOARD) UniquePasteboard
: public base::RefCounted<UniquePasteboard> {
public:
UniquePasteboard();
@@ -31,7 +31,7 @@ class UI_BASE_EXPORT UniquePasteboard
base::scoped_nsobject<NSPasteboard> pasteboard_;
};
-class UI_BASE_EXPORT ClipboardUtil {
+class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardUtil {
public:
// Returns an NSPasteboardItem that represents the given |url|.
// |url| must not be nil.
diff --git a/chromium/ui/base/clipboard/clipboard_util_mac.mm b/chromium/ui/base/clipboard/clipboard_util_mac.mm
index 3611b997d66..1707d3089c2 100644
--- a/chromium/ui/base/clipboard/clipboard_util_mac.mm
+++ b/chromium/ui/base/clipboard/clipboard_util_mac.mm
@@ -13,6 +13,7 @@ namespace ui {
NSString* const kUTTypeURLName = @"public.url-name";
namespace {
+
NSString* const kWebURLsWithTitlesPboardType = @"WebURLsWithTitlesPboardType";
// It's much more convenient to return an NSString than a
@@ -23,6 +24,72 @@ NSString* UTIFromPboardType(NSString* type) {
kUTTagClassNSPboardType, base::mac::NSToCFCast(type), kUTTypeData))
autorelease];
}
+
+bool ReadWebURLsWithTitlesPboardType(NSPasteboard* pboard,
+ NSArray** urls,
+ NSArray** titles) {
+ NSArray* bookmarkPairs = base::mac::ObjCCast<NSArray>([pboard
+ propertyListForType:UTIFromPboardType(kWebURLsWithTitlesPboardType)]);
+ if (!bookmarkPairs)
+ return false;
+
+ if ([bookmarkPairs count] != 2)
+ return false;
+
+ NSArray* urlsArr = base::mac::ObjCCast<NSArray>(bookmarkPairs[0]);
+ NSArray* titlesArr = base::mac::ObjCCast<NSArray>(bookmarkPairs[1]);
+
+ if (!urlsArr || !titlesArr)
+ return false;
+ if ([urlsArr count] < 1)
+ return false;
+ if ([urlsArr count] != [titlesArr count])
+ return false;
+
+ for (id obj in urlsArr) {
+ if (![obj isKindOfClass:[NSString class]])
+ return false;
+ }
+
+ for (id obj in titlesArr) {
+ if (![obj isKindOfClass:[NSString class]])
+ return false;
+ }
+
+ *urls = urlsArr;
+ *titles = titlesArr;
+ return true;
+}
+
+bool ReadURLItemsWithTitles(NSPasteboard* pboard,
+ NSArray** urls,
+ NSArray** titles) {
+ NSMutableArray* urlsArr = [NSMutableArray array];
+ NSMutableArray* titlesArr = [NSMutableArray array];
+
+ NSArray* items = [pboard pasteboardItems];
+ for (NSPasteboardItem* item : items) {
+ NSString* url = [item stringForType:base::mac::CFToNSCast(kUTTypeURL)];
+ NSString* title = [item stringForType:kUTTypeURLName];
+
+ if (url) {
+ [urlsArr addObject:url];
+ if (title)
+ [titlesArr addObject:title];
+ else
+ [titlesArr addObject:@""];
+ }
+ }
+
+ if ([urlsArr count]) {
+ *urls = urlsArr;
+ *titles = titlesArr;
+ return true;
+ } else {
+ return false;
+ }
+}
+
} // namespace
UniquePasteboard::UniquePasteboard()
@@ -142,37 +209,8 @@ void ClipboardUtil::AddDataToPasteboard(NSPasteboard* pboard,
bool ClipboardUtil::URLsAndTitlesFromPasteboard(NSPasteboard* pboard,
NSArray** urls,
NSArray** titles) {
- NSArray* bookmarkPairs = base::mac::ObjCCast<NSArray>([pboard
- propertyListForType:UTIFromPboardType(kWebURLsWithTitlesPboardType)]);
- if (!bookmarkPairs)
- return false;
-
- if ([bookmarkPairs count] != 2)
- return false;
-
- NSArray* urlsArr = base::mac::ObjCCast<NSArray>(bookmarkPairs[0]);
- NSArray* titlesArr = base::mac::ObjCCast<NSArray>(bookmarkPairs[1]);
-
- if (!urlsArr || !titlesArr)
- return false;
- if ([urlsArr count] < 1)
- return false;
- if ([urlsArr count] != [titlesArr count])
- return false;
-
- for (id obj in urlsArr) {
- if (![obj isKindOfClass:[NSString class]])
- return false;
- }
-
- for (id obj in titlesArr) {
- if (![obj isKindOfClass:[NSString class]])
- return false;
- }
-
- *urls = urlsArr;
- *titles = titlesArr;
- return true;
+ return ReadWebURLsWithTitlesPboardType(pboard, urls, titles) ||
+ ReadURLItemsWithTitles(pboard, urls, titles);
}
// static
diff --git a/chromium/ui/base/clipboard/clipboard_util_win.cc b/chromium/ui/base/clipboard/clipboard_util_win.cc
index 5d16a369ee7..077df5a6d48 100644
--- a/chromium/ui/base/clipboard/clipboard_util_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_util_win.cc
@@ -9,7 +9,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
@@ -17,7 +17,7 @@
#include "base/win/scoped_hglobal.h"
#include "base/win/shlwapi.h"
#include "net/base/filename_util.h"
-#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "url/gurl.h"
@@ -25,13 +25,13 @@ namespace ui {
namespace {
-bool HasData(IDataObject* data_object, const Clipboard::FormatType& format) {
+bool HasData(IDataObject* data_object, const ClipboardFormatType& format) {
FORMATETC format_etc = format.ToFormatEtc();
return SUCCEEDED(data_object->QueryGetData(&format_etc));
}
bool GetData(IDataObject* data_object,
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
STGMEDIUM* medium) {
FORMATETC format_etc = format.ToFormatEtc();
return SUCCEEDED(data_object->GetData(&format_etc, medium));
@@ -44,7 +44,7 @@ bool GetUrlFromHDrop(IDataObject* data_object,
bool success = false;
STGMEDIUM medium;
- if (!GetData(data_object, Clipboard::GetCFHDropFormatType(), &medium))
+ if (!GetData(data_object, ClipboardFormatType::GetCFHDropType(), &medium))
return false;
{
@@ -54,15 +54,11 @@ bool GetUrlFromHDrop(IDataObject* data_object,
return false;
wchar_t filename[MAX_PATH];
- if (DragQueryFileW(hdrop.get(), 0, filename, arraysize(filename))) {
+ if (DragQueryFileW(hdrop.get(), 0, filename, base::size(filename))) {
wchar_t url_buffer[INTERNET_MAX_URL_LENGTH];
if (0 == _wcsicmp(PathFindExtensionW(filename), L".url") &&
- GetPrivateProfileStringW(L"InternetShortcut",
- L"url",
- 0,
- url_buffer,
- arraysize(url_buffer),
- filename)) {
+ GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, url_buffer,
+ base::size(url_buffer), filename)) {
*url = GURL(url_buffer);
PathRemoveExtension(filename);
title->assign(PathFindFileName(filename));
@@ -93,34 +89,34 @@ void SplitUrlAndTitle(const base::string16& str,
bool ClipboardUtil::HasUrl(IDataObject* data_object, bool convert_filenames) {
DCHECK(data_object);
- return HasData(data_object, Clipboard::GetMozUrlFormatType()) ||
- HasData(data_object, Clipboard::GetUrlWFormatType()) ||
- HasData(data_object, Clipboard::GetUrlFormatType()) ||
+ return HasData(data_object, ClipboardFormatType::GetMozUrlType()) ||
+ HasData(data_object, ClipboardFormatType::GetUrlWType()) ||
+ HasData(data_object, ClipboardFormatType::GetUrlType()) ||
(convert_filenames && HasFilenames(data_object));
}
bool ClipboardUtil::HasFilenames(IDataObject* data_object) {
DCHECK(data_object);
- return HasData(data_object, Clipboard::GetCFHDropFormatType()) ||
- HasData(data_object, Clipboard::GetFilenameWFormatType()) ||
- HasData(data_object, Clipboard::GetFilenameFormatType());
+ return HasData(data_object, ClipboardFormatType::GetCFHDropType()) ||
+ HasData(data_object, ClipboardFormatType::GetFilenameWType()) ||
+ HasData(data_object, ClipboardFormatType::GetFilenameType());
}
bool ClipboardUtil::HasFileContents(IDataObject* data_object) {
DCHECK(data_object);
- return HasData(data_object, Clipboard::GetFileContentZeroFormatType());
+ return HasData(data_object, ClipboardFormatType::GetFileContentZeroType());
}
bool ClipboardUtil::HasHtml(IDataObject* data_object) {
DCHECK(data_object);
- return HasData(data_object, Clipboard::GetHtmlFormatType()) ||
- HasData(data_object, Clipboard::GetTextHtmlFormatType());
+ return HasData(data_object, ClipboardFormatType::GetHtmlType()) ||
+ HasData(data_object, ClipboardFormatType::GetTextHtmlType());
}
bool ClipboardUtil::HasPlainText(IDataObject* data_object) {
DCHECK(data_object);
- return HasData(data_object, Clipboard::GetPlainTextWFormatType()) ||
- HasData(data_object, Clipboard::GetPlainTextFormatType());
+ return HasData(data_object, ClipboardFormatType::GetPlainTextWType()) ||
+ HasData(data_object, ClipboardFormatType::GetPlainTextType());
}
bool ClipboardUtil::GetUrl(IDataObject* data_object,
@@ -136,8 +132,8 @@ bool ClipboardUtil::GetUrl(IDataObject* data_object,
if (GetUrlFromHDrop(data_object, url, title))
return true;
- if (GetData(data_object, Clipboard::GetMozUrlFormatType(), &store) ||
- GetData(data_object, Clipboard::GetUrlWFormatType(), &store)) {
+ if (GetData(data_object, ClipboardFormatType::GetMozUrlType(), &store) ||
+ GetData(data_object, ClipboardFormatType::GetUrlWType(), &store)) {
{
// Mozilla URL format or unicode URL
base::win::ScopedHGlobal<wchar_t*> data(store.hGlobal);
@@ -147,7 +143,7 @@ bool ClipboardUtil::GetUrl(IDataObject* data_object,
return url->is_valid();
}
- if (GetData(data_object, Clipboard::GetUrlFormatType(), &store)) {
+ if (GetData(data_object, ClipboardFormatType::GetUrlType(), &store)) {
{
// URL using ascii
base::win::ScopedHGlobal<char*> data(store.hGlobal);
@@ -176,7 +172,7 @@ bool ClipboardUtil::GetFilenames(IDataObject* data_object,
return false;
STGMEDIUM medium;
- if (GetData(data_object, Clipboard::GetCFHDropFormatType(), &medium)) {
+ if (GetData(data_object, ClipboardFormatType::GetCFHDropType(), &medium)) {
{
base::win::ScopedHGlobal<HDROP> hdrop(medium.hGlobal);
if (!hdrop.get())
@@ -195,7 +191,7 @@ bool ClipboardUtil::GetFilenames(IDataObject* data_object,
return !filenames->empty();
}
- if (GetData(data_object, Clipboard::GetFilenameWFormatType(), &medium)) {
+ if (GetData(data_object, ClipboardFormatType::GetFilenameWType(), &medium)) {
{
// filename using unicode
base::win::ScopedHGlobal<wchar_t*> data(medium.hGlobal);
@@ -206,7 +202,7 @@ bool ClipboardUtil::GetFilenames(IDataObject* data_object,
return true;
}
- if (GetData(data_object, Clipboard::GetFilenameFormatType(), &medium)) {
+ if (GetData(data_object, ClipboardFormatType::GetFilenameType(), &medium)) {
{
// filename using ascii
base::win::ScopedHGlobal<char*> data(medium.hGlobal);
@@ -227,7 +223,7 @@ bool ClipboardUtil::GetPlainText(IDataObject* data_object,
return false;
STGMEDIUM store;
- if (GetData(data_object, Clipboard::GetPlainTextWFormatType(), &store)) {
+ if (GetData(data_object, ClipboardFormatType::GetPlainTextWType(), &store)) {
{
// Unicode text
base::win::ScopedHGlobal<wchar_t*> data(store.hGlobal);
@@ -237,7 +233,7 @@ bool ClipboardUtil::GetPlainText(IDataObject* data_object,
return true;
}
- if (GetData(data_object, Clipboard::GetPlainTextFormatType(), &store)) {
+ if (GetData(data_object, ClipboardFormatType::GetPlainTextType(), &store)) {
{
// ascii text
base::win::ScopedHGlobal<char*> data(store.hGlobal);
@@ -263,8 +259,8 @@ bool ClipboardUtil::GetHtml(IDataObject* data_object,
DCHECK(data_object && html && base_url);
STGMEDIUM store;
- if (HasData(data_object, Clipboard::GetHtmlFormatType()) &&
- GetData(data_object, Clipboard::GetHtmlFormatType(), &store)) {
+ if (HasData(data_object, ClipboardFormatType::GetHtmlType()) &&
+ GetData(data_object, ClipboardFormatType::GetHtmlType(), &store)) {
{
// MS CF html
base::win::ScopedHGlobal<char*> data(store.hGlobal);
@@ -277,10 +273,10 @@ bool ClipboardUtil::GetHtml(IDataObject* data_object,
return true;
}
- if (!HasData(data_object, Clipboard::GetTextHtmlFormatType()))
+ if (!HasData(data_object, ClipboardFormatType::GetTextHtmlType()))
return false;
- if (!GetData(data_object, Clipboard::GetTextHtmlFormatType(), &store))
+ if (!GetData(data_object, ClipboardFormatType::GetTextHtmlType(), &store))
return false;
{
@@ -295,15 +291,15 @@ bool ClipboardUtil::GetHtml(IDataObject* data_object,
bool ClipboardUtil::GetFileContents(IDataObject* data_object,
base::string16* filename, std::string* file_contents) {
DCHECK(data_object && filename && file_contents);
- if (!HasData(data_object, Clipboard::GetFileContentZeroFormatType()) &&
- !HasData(data_object, Clipboard::GetFileDescriptorFormatType()))
+ if (!HasData(data_object, ClipboardFormatType::GetFileContentZeroType()) &&
+ !HasData(data_object, ClipboardFormatType::GetFileDescriptorType()))
return false;
STGMEDIUM content;
// The call to GetData can be very slow depending on what is in
// |data_object|.
- if (GetData(
- data_object, Clipboard::GetFileContentZeroFormatType(), &content)) {
+ if (GetData(data_object, ClipboardFormatType::GetFileContentZeroType(),
+ &content)) {
if (TYMED_HGLOBAL == content.tymed) {
base::win::ScopedHGlobal<char*> data(content.hGlobal);
file_contents->assign(data.get(), data.Size());
@@ -312,8 +308,7 @@ bool ClipboardUtil::GetFileContents(IDataObject* data_object,
}
STGMEDIUM description;
- if (GetData(data_object,
- Clipboard::GetFileDescriptorFormatType(),
+ if (GetData(data_object, ClipboardFormatType::GetFileDescriptorType(),
&description)) {
{
base::win::ScopedHGlobal<FILEGROUPDESCRIPTOR*> fgd(description.hGlobal);
@@ -331,11 +326,12 @@ bool ClipboardUtil::GetWebCustomData(
std::unordered_map<base::string16, base::string16>* custom_data) {
DCHECK(data_object && custom_data);
- if (!HasData(data_object, Clipboard::GetWebCustomDataFormatType()))
+ if (!HasData(data_object, ClipboardFormatType::GetWebCustomDataType()))
return false;
STGMEDIUM store;
- if (GetData(data_object, Clipboard::GetWebCustomDataFormatType(), &store)) {
+ if (GetData(data_object, ClipboardFormatType::GetWebCustomDataType(),
+ &store)) {
{
base::win::ScopedHGlobal<char*> data(store.hGlobal);
ReadCustomDataIntoMap(data.get(), data.Size(), custom_data);
diff --git a/chromium/ui/base/clipboard/clipboard_util_win.h b/chromium/ui/base/clipboard/clipboard_util_win.h
index 0a481851f14..b4d0ae9528f 100644
--- a/chromium/ui/base/clipboard/clipboard_util_win.h
+++ b/chromium/ui/base/clipboard/clipboard_util_win.h
@@ -13,14 +13,14 @@
#include <unordered_map>
#include <vector>
+#include "base/component_export.h"
#include "base/strings/string16.h"
-#include "ui/base/ui_base_export.h"
class GURL;
namespace ui {
-class UI_BASE_EXPORT ClipboardUtil {
+class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardUtil {
public:
/////////////////////////////////////////////////////////////////////////////
// These methods check to see if |data_object| has the requested type.
@@ -72,7 +72,6 @@ class UI_BASE_EXPORT ClipboardUtil {
size_t* fragment_start,
size_t* fragment_end);
};
-
}
#endif // UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_WIN_H_
diff --git a/chromium/ui/base/clipboard/clipboard_win.cc b/chromium/ui/base/clipboard/clipboard_win.cc
index 1857bfa07ce..49654c95675 100644
--- a/chromium/ui/base/clipboard/clipboard_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_win.cc
@@ -28,6 +28,7 @@
#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_constants.h"
#include "ui/base/clipboard/clipboard_util_win.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/gfx/canvas.h"
@@ -220,201 +221,6 @@ void TrimAfterNull(StringType* result) {
} // namespace
-// Clipboard::FormatType implementation.
-Clipboard::FormatType::FormatType() : data_() {}
-
-Clipboard::FormatType::FormatType(UINT native_format) : data_() {
- // There's no good way to actually initialize this in the constructor in
- // C++03.
- data_.cfFormat = static_cast<CLIPFORMAT>(native_format);
- data_.dwAspect = DVASPECT_CONTENT;
- data_.lindex = -1;
- data_.tymed = TYMED_HGLOBAL;
-}
-
-Clipboard::FormatType::FormatType(UINT native_format, LONG index) : data_() {
- // There's no good way to actually initialize this in the constructor in
- // C++03.
- data_.cfFormat = static_cast<CLIPFORMAT>(native_format);
- data_.dwAspect = DVASPECT_CONTENT;
- data_.lindex = index;
- data_.tymed = TYMED_HGLOBAL;
-}
-
-Clipboard::FormatType::~FormatType() {
-}
-
-std::string Clipboard::FormatType::Serialize() const {
- return base::IntToString(data_.cfFormat);
-}
-
-// static
-Clipboard::FormatType Clipboard::FormatType::Deserialize(
- const std::string& serialization) {
- int clipboard_format = -1;
- if (!base::StringToInt(serialization, &clipboard_format)) {
- NOTREACHED();
- return FormatType();
- }
- return FormatType(clipboard_format);
-}
-
-bool Clipboard::FormatType::operator<(const FormatType& other) const {
- return data_.cfFormat < other.data_.cfFormat;
-}
-
-bool Clipboard::FormatType::Equals(const FormatType& other) const {
- return data_.cfFormat == other.data_.cfFormat;
-}
-
-// Various predefined FormatTypes.
-// static
-Clipboard::FormatType Clipboard::GetFormatType(
- const std::string& format_string) {
- return FormatType(
- ::RegisterClipboardFormat(base::ASCIIToUTF16(format_string).c_str()));
-}
-
-// The following formats can be referenced by ClipboardUtilWin::GetPlainText.
-// For reasons (COM), they must be initialized in a thread-safe manner.
-// TODO(dcheng): We probably need to make static initialization of "known"
-// FormatTypes thread-safe on all platforms.
-#define CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(name, ...) \
- struct FormatTypeArgumentForwarder : public FormatType { \
- FormatTypeArgumentForwarder() : FormatType(__VA_ARGS__) { } \
- }; \
- static base::LazyInstance<FormatTypeArgumentForwarder>::Leaky name = \
- LAZY_INSTANCE_INITIALIZER
-// static
-const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(CFSTR_INETURLA));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(CFSTR_INETURLW));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetMozUrlFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(L"text/x-moz-url"));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type, CF_TEXT);
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type, CF_UNICODETEXT);
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(CFSTR_FILENAMEA));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(CFSTR_FILENAMEW));
- return type.Get();
-}
-
-// MS HTML Format
-// static
-const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(L"HTML Format"));
- return type.Get();
-}
-
-// MS RTF Format
-// static
-const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(L"Rich Text Format"));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type, CF_BITMAP);
- return type.Get();
-}
-
-// Firefox text/html
-// static
-const Clipboard::FormatType& Clipboard::GetTextHtmlFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(L"text/html"));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetCFHDropFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type, CF_HDROP);
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFileDescriptorFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetFileContentZeroFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0);
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetIDListFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(CFSTR_SHELLIDLIST));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type,
- ::RegisterClipboardFormat(L"WebKit Smart Paste Format"));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
- // TODO(dcheng): This name is temporary. See http://crbug.com/106449.
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type,
- ::RegisterClipboardFormat(L"Chromium Web Custom MIME Data Format"));
- return type.Get();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
- CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type,
- ::RegisterClipboardFormat(L"Chromium Pepper MIME Data Format"));
- return type.Get();
-}
-#undef CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE
-
// Clipboard factory method.
// static
Clipboard* Clipboard::Create() {
@@ -437,7 +243,7 @@ uint64_t ClipboardWin::GetSequenceNumber(ClipboardType type) const {
return ::GetClipboardSequenceNumber();
}
-bool ClipboardWin::IsFormatAvailable(const Clipboard::FormatType& format,
+bool ClipboardWin::IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const {
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
return ::IsClipboardFormatAvailable(format.ToFormatEtc().cfFormat) != FALSE;
@@ -462,11 +268,13 @@ void ClipboardWin::ReadAvailableTypes(ClipboardType type,
types->clear();
if (::IsClipboardFormatAvailable(
- GetPlainTextFormatType().ToFormatEtc().cfFormat))
+ ClipboardFormatType::GetPlainTextType().ToFormatEtc().cfFormat))
types->push_back(base::UTF8ToUTF16(kMimeTypeText));
- if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToFormatEtc().cfFormat))
+ if (::IsClipboardFormatAvailable(
+ ClipboardFormatType::GetHtmlType().ToFormatEtc().cfFormat))
types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
- if (::IsClipboardFormatAvailable(GetRtfFormatType().ToFormatEtc().cfFormat))
+ if (::IsClipboardFormatAvailable(
+ ClipboardFormatType::GetRtfType().ToFormatEtc().cfFormat))
types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
if (::IsClipboardFormatAvailable(CF_DIB))
types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
@@ -477,8 +285,8 @@ void ClipboardWin::ReadAvailableTypes(ClipboardType type,
if (!clipboard.Acquire(GetClipboardWindow()))
return;
- HANDLE hdata =
- ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat);
+ HANDLE hdata = ::GetClipboardData(
+ ClipboardFormatType::GetWebCustomDataType().ToFormatEtc().cfFormat);
if (!hdata)
return;
@@ -555,7 +363,8 @@ void ClipboardWin::ReadHTML(ClipboardType type,
if (!clipboard.Acquire(GetClipboardWindow()))
return;
- HANDLE data = ::GetClipboardData(GetHtmlFormatType().ToFormatEtc().cfFormat);
+ HANDLE data = ::GetClipboardData(
+ ClipboardFormatType::GetHtmlType().ToFormatEtc().cfFormat);
if (!data)
return;
@@ -594,7 +403,7 @@ void ClipboardWin::ReadHTML(ClipboardType type,
void ClipboardWin::ReadRTF(ClipboardType type, std::string* result) const {
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
- ReadData(GetRtfFormatType(), result);
+ ReadData(ClipboardFormatType::GetRtfType(), result);
TrimAfterNull(result);
}
@@ -690,8 +499,8 @@ void ClipboardWin::ReadCustomData(ClipboardType clipboard_type,
if (!clipboard.Acquire(GetClipboardWindow()))
return;
- HANDLE hdata =
- ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat);
+ HANDLE hdata = ::GetClipboardData(
+ ClipboardFormatType::GetWebCustomDataType().ToFormatEtc().cfFormat);
if (!hdata)
return;
@@ -711,7 +520,8 @@ void ClipboardWin::ReadBookmark(base::string16* title, std::string* url) const {
if (!clipboard.Acquire(GetClipboardWindow()))
return;
- HANDLE data = ::GetClipboardData(GetUrlWFormatType().ToFormatEtc().cfFormat);
+ HANDLE data = ::GetClipboardData(
+ ClipboardFormatType::GetUrlWType().ToFormatEtc().cfFormat);
if (!data)
return;
@@ -723,7 +533,7 @@ void ClipboardWin::ReadBookmark(base::string16* title, std::string* url) const {
ParseBookmarkClipboardFormat(bookmark, title, url);
}
-void ClipboardWin::ReadData(const FormatType& format,
+void ClipboardWin::ReadData(const ClipboardFormatType& format,
std::string* result) const {
if (!result) {
NOTREACHED();
@@ -779,11 +589,12 @@ void ClipboardWin::WriteHTML(const char* markup_data,
std::string html_fragment = ClipboardUtil::HtmlToCFHtml(markup, url);
HGLOBAL glob = CreateGlobalData(html_fragment);
- WriteToClipboard(Clipboard::GetHtmlFormatType().ToFormatEtc().cfFormat, glob);
+ WriteToClipboard(ClipboardFormatType::GetHtmlType().ToFormatEtc().cfFormat,
+ glob);
}
void ClipboardWin::WriteRTF(const char* rtf_data, size_t data_len) {
- WriteData(GetRtfFormatType(), rtf_data, data_len);
+ WriteData(ClipboardFormatType::GetRtfType(), rtf_data, data_len);
}
void ClipboardWin::WriteBookmark(const char* title_data,
@@ -797,13 +608,15 @@ void ClipboardWin::WriteBookmark(const char* title_data,
base::string16 wide_bookmark = base::UTF8ToUTF16(bookmark);
HGLOBAL glob = CreateGlobalData(wide_bookmark);
- WriteToClipboard(GetUrlWFormatType().ToFormatEtc().cfFormat, glob);
+ WriteToClipboard(ClipboardFormatType::GetUrlWType().ToFormatEtc().cfFormat,
+ glob);
}
void ClipboardWin::WriteWebSmartPaste() {
DCHECK(clipboard_owner_->hwnd() != NULL);
- ::SetClipboardData(GetWebKitSmartPasteFormatType().ToFormatEtc().cfFormat,
- NULL);
+ ::SetClipboardData(
+ ClipboardFormatType::GetWebKitSmartPasteType().ToFormatEtc().cfFormat,
+ NULL);
}
void ClipboardWin::WriteBitmap(const SkBitmap& in_bitmap) {
@@ -849,7 +662,7 @@ void ClipboardWin::WriteBitmap(const SkBitmap& in_bitmap) {
::ReleaseDC(NULL, dc);
}
-void ClipboardWin::WriteData(const FormatType& format,
+void ClipboardWin::WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) {
HGLOBAL hdata = ::GlobalAlloc(GMEM_MOVEABLE, data_len);
diff --git a/chromium/ui/base/clipboard/clipboard_win.h b/chromium/ui/base/clipboard/clipboard_win.h
index 54e34d7f5ce..68e3ce81e13 100644
--- a/chromium/ui/base/clipboard/clipboard_win.h
+++ b/chromium/ui/base/clipboard/clipboard_win.h
@@ -35,7 +35,7 @@ class ClipboardWin : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
uint64_t GetSequenceNumber(ClipboardType type) const override;
- bool IsFormatAvailable(const FormatType& format,
+ bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const override;
void Clear(ClipboardType type) override;
void ReadAvailableTypes(ClipboardType type,
@@ -54,7 +54,8 @@ class ClipboardWin : public Clipboard {
const base::string16& type,
base::string16* result) const override;
void ReadBookmark(base::string16* title, std::string* url) const override;
- void ReadData(const FormatType& format, std::string* result) const override;
+ void ReadData(const ClipboardFormatType& format,
+ std::string* result) const override;
void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
void WriteText(const char* text_data, size_t text_len) override;
void WriteHTML(const char* markup_data,
@@ -68,7 +69,7 @@ class ClipboardWin : public Clipboard {
size_t url_len) override;
void WriteWebSmartPaste() override;
void WriteBitmap(const SkBitmap& bitmap) override;
- void WriteData(const FormatType& format,
+ void WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) override;
diff --git a/chromium/ui/base/clipboard/custom_data_helper.h b/chromium/ui/base/clipboard/custom_data_helper.h
index 6da8234aaa3..7d980f0a8c5 100644
--- a/chromium/ui/base/clipboard/custom_data_helper.h
+++ b/chromium/ui/base/clipboard/custom_data_helper.h
@@ -15,46 +15,39 @@
#include <unordered_map>
#include <vector>
+#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
-#include "ui/base/ui_base_export.h"
namespace base {
class Pickle;
}
-#if defined(OS_MACOSX)
-#ifdef __OBJC__
-@class NSString;
-#else
-class NSString;
-#endif
-#endif // defined(OS_MACOSX)
-
namespace ui {
-#if defined(OS_MACOSX) && !defined(USE_AURA)
-UI_BASE_EXPORT extern NSString* const kWebCustomDataPboardType;
-#endif
-
-UI_BASE_EXPORT void ReadCustomDataTypes(const void* data,
- size_t data_length,
- std::vector<base::string16>* types);
-UI_BASE_EXPORT void ReadCustomDataForType(const void* data,
- size_t data_length,
- const base::string16& type,
- base::string16* result);
-UI_BASE_EXPORT void ReadCustomDataIntoMap(
+COMPONENT_EXPORT(BASE_CLIPBOARD)
+void ReadCustomDataTypes(const void* data,
+ size_t data_length,
+ std::vector<base::string16>* types);
+COMPONENT_EXPORT(BASE_CLIPBOARD)
+void ReadCustomDataForType(const void* data,
+ size_t data_length,
+ const base::string16& type,
+ base::string16* result);
+COMPONENT_EXPORT(BASE_CLIPBOARD)
+void ReadCustomDataIntoMap(
const void* data,
size_t data_length,
std::unordered_map<base::string16, base::string16>* result);
-UI_BASE_EXPORT void WriteCustomDataToPickle(
+COMPONENT_EXPORT(BASE_CLIPBOARD)
+void WriteCustomDataToPickle(
const std::unordered_map<base::string16, base::string16>& data,
base::Pickle* pickle);
-UI_BASE_EXPORT void WriteCustomDataToPickle(
+COMPONENT_EXPORT(BASE_CLIPBOARD)
+void WriteCustomDataToPickle(
const base::flat_map<base::string16, base::string16>& data,
base::Pickle* pickle);
diff --git a/chromium/ui/base/clipboard/scoped_clipboard_writer.cc b/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
index 12680a66d17..a2590645a6d 100644
--- a/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
+++ b/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
@@ -11,6 +11,7 @@
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/escape.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/gfx/geometry/size.h"
namespace ui {
@@ -88,9 +89,11 @@ void ScopedClipboardWriter::WriteWebSmartPaste() {
}
void ScopedClipboardWriter::WriteImage(const SkBitmap& bitmap) {
- if (bitmap.drawsNothing()) {
+ if (bitmap.drawsNothing())
return;
- }
+ // TODO(crbug.com/918717): Remove CHECK if no crashes occur on it in canary.
+ CHECK(bitmap.getPixels());
+
bitmap_ = bitmap;
// TODO(dcheng): This is slightly less horrible than what we used to do, but
// only very slightly less.
@@ -105,7 +108,7 @@ void ScopedClipboardWriter::WriteImage(const SkBitmap& bitmap) {
void ScopedClipboardWriter::WritePickledData(
const base::Pickle& pickle,
- const Clipboard::FormatType& format) {
+ const ClipboardFormatType& format) {
std::string format_string = format.Serialize();
Clipboard::ObjectMapParam format_parameter(format_string.begin(),
format_string.end());
diff --git a/chromium/ui/base/clipboard/scoped_clipboard_writer.h b/chromium/ui/base/clipboard/scoped_clipboard_writer.h
index 385900eb67d..084d5fe141f 100644
--- a/chromium/ui/base/clipboard/scoped_clipboard_writer.h
+++ b/chromium/ui/base/clipboard/scoped_clipboard_writer.h
@@ -13,11 +13,11 @@
#include <string>
+#include "base/component_export.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/ui_base_export.h"
namespace base {
class Pickle;
@@ -27,7 +27,7 @@ namespace ui {
// This class is a wrapper for |Clipboard| that handles packing data
// into a Clipboard::ObjectMap.
-class UI_BASE_EXPORT ScopedClipboardWriter {
+class COMPONENT_EXPORT(BASE_CLIPBOARD) ScopedClipboardWriter {
public:
// Create an instance that is a simple wrapper around the clipboard of the
// given type.
@@ -59,7 +59,7 @@ class UI_BASE_EXPORT ScopedClipboardWriter {
// Adds arbitrary pickled data to clipboard.
void WritePickledData(const base::Pickle& pickle,
- const Clipboard::FormatType& format);
+ const ClipboardFormatType& format);
// Adds custom data to clipboard.
void WriteData(const std::string& type, const std::string& data);
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 c755c4f6a39..bb39146ff0f 100644
--- a/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.mm
+++ b/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.mm
@@ -10,8 +10,8 @@
#include "base/files/file_path.h"
#include "base/location.h"
#import "base/mac/foundation_util.h"
-#include "base/macros.h"
#include "base/native_library.h"
+#include "base/stl_util.h"
#include "ui/gfx/animation/tween.h"
// The window animations in this file use private APIs as described here:
@@ -325,7 +325,7 @@ bool AreWindowServerEffectsDisabled() {
};
CGFloat scale = 1;
- for (int i = arraysize(frames) - 1; i >= 0; --i) {
+ for (int i = base::size(frames) - 1; i >= 0; --i) {
if (value >= frames[i].value) {
CGFloat delta = frames[i + 1].value - frames[i].value;
CGFloat frame_progress = (value - frames[i].value) / delta;
diff --git a/chromium/ui/base/cocoa/menu_controller_unittest.mm b/chromium/ui/base/cocoa/menu_controller_unittest.mm
index 6a3647306b9..a4a0627b600 100644
--- a/chromium/ui/base/cocoa/menu_controller_unittest.mm
+++ b/chromium/ui/base/cocoa/menu_controller_unittest.mm
@@ -555,7 +555,7 @@ TEST_F(MenuControllerTest, Dynamic) {
delegate.SetDynamicLabel(second);
const gfx::Image& icon =
ResourceBundle::GetSharedInstance().GetNativeImageNamed(
- IDR_EMOJI_FAVICON);
+ IDR_DEFAULT_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.mm b/chromium/ui/base/cocoa/remote_accessibility_api.mm
index 8a6d9d1f2ab..b901d785377 100644
--- a/chromium/ui/base/cocoa/remote_accessibility_api.mm
+++ b/chromium/ui/base/cocoa/remote_accessibility_api.mm
@@ -18,6 +18,8 @@ std::vector<uint8_t> RemoteAccessibility::GetTokenForLocalElement(id element) {
base::scoped_nsobject<NSAccessibilityRemoteUIElement>
RemoteAccessibility::GetRemoteElementFromToken(
const std::vector<uint8_t>& token) {
+ if (token.empty())
+ return base::scoped_nsobject<NSAccessibilityRemoteUIElement>();
base::scoped_nsobject<NSData> data(
[[NSData alloc] initWithBytes:token.data() length:token.size()]);
return base::scoped_nsobject<NSAccessibilityRemoteUIElement>(
diff --git a/chromium/ui/base/cocoa/remote_views_window.h b/chromium/ui/base/cocoa/remote_views_window.h
new file mode 100644
index 00000000000..634d54a9390
--- /dev/null
+++ b/chromium/ui/base/cocoa/remote_views_window.h
@@ -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.
+
+#ifndef UI_BASE_COCOA_REMOTE_VIEWS_WINDOW_H_
+#define UI_BASE_COCOA_REMOTE_VIEWS_WINDOW_H_
+
+#include "ui/base/ui_base_export.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+
+// Returns true if the specified NSWindow corresponds to an NSWindow that is
+// being viewed in a remote process.
+bool UI_BASE_EXPORT IsWindowUsingRemoteViews(gfx::NativeWindow window);
+
+// Create a transparent NSWindow that is in the same position as |window|,
+// but is at the ModalPanel window level, so that it will appear over all
+// other window.
+NSWindow* UI_BASE_EXPORT
+CreateTransparentRemoteViewsClone(gfx::NativeWindow window);
+
+} // namespace ui
+
+#endif // UI_BASE_COCOA_REMOTE_VIEWS_WINDOW_H_
diff --git a/chromium/ui/base/cocoa/remote_views_window.mm b/chromium/ui/base/cocoa/remote_views_window.mm
new file mode 100644
index 00000000000..c9531ef7241
--- /dev/null
+++ b/chromium/ui/base/cocoa/remote_views_window.mm
@@ -0,0 +1,45 @@
+// 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_views_window.h"
+
+#import <Cocoa/Cocoa.h>
+
+// An NSWindow is using RemoteMacViews if it has no BridgedNativeWidgetImpl.
+// This is the most expedient method of determining if an NSWindow uses
+// RemoteMacViews.
+namespace views {
+class BridgedNativeWidgetImpl;
+} // namespace views
+
+@interface NSWindow (Private)
+- (views::BridgedNativeWidgetImpl*)bridgeImpl;
+@end
+
+namespace ui {
+
+bool IsWindowUsingRemoteViews(gfx::NativeWindow gfx_window) {
+ NSWindow* ns_window = gfx_window.GetNativeNSWindow();
+ if ([ns_window respondsToSelector:@selector(bridgeImpl)]) {
+ if (![ns_window bridgeImpl])
+ return true;
+ }
+ return false;
+}
+
+NSWindow* UI_BASE_EXPORT
+CreateTransparentRemoteViewsClone(gfx::NativeWindow remote_window) {
+ DCHECK(IsWindowUsingRemoteViews(remote_window));
+ NSWindow* window = [[NSWindow alloc]
+ initWithContentRect:[remote_window.GetNativeNSWindow() frame]
+ styleMask:NSWindowStyleMaskBorderless
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ [window setAlphaValue:0];
+ [window makeKeyAndOrderFront:nil];
+ [window setLevel:NSModalPanelWindowLevel];
+ return window;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cocoa/views_hostable.h b/chromium/ui/base/cocoa/views_hostable.h
index 68c5cc56f19..f8160f94ad6 100644
--- a/chromium/ui/base/cocoa/views_hostable.h
+++ b/chromium/ui/base/cocoa/views_hostable.h
@@ -41,28 +41,28 @@ class ViewsHostableView {
virtual void OnHostableViewDestroying() = 0;
};
- // Called when the content::WebContentsView's NSView is added as a subview of
- // the views::View's NSView (note that these are the browser-side NSViews).
- // This is responsible for:
+ // Called to add the content::WebContentsView's NSView as a subview of the
+ // views::View's NSView. This is responsible for:
// - Adding the WebContentsView's ui::Layer to the parent's ui::Layer tree.
// - Stitching together the accessibility tree between the views::View and
// the WebContentsView.
- // - Stitching together any app-shim-side NSViews.
- virtual void OnViewsHostableAttached(Host* host) = 0;
+ // - Adding the WebContents browser-side and app-shim-side NSViews as children
+ // to the views::View's NSViews.
+ virtual void ViewsHostableAttach(Host* host) = 0;
// Called when the WebContentsView's NSView has been removed from the
// views::View's NSView. This is responsible for un-doing all of the actions
// taken when attaching.
- virtual void OnViewsHostableDetached() = 0;
+ virtual void ViewsHostableDetach() = 0;
- // Called when the WebContentsView's NSView is to be shown or resized.
- virtual void OnViewsHostableShow(const gfx::Rect& bounds_in_window) = 0;
+ // Resize the WebContentsView's NSView.
+ virtual void ViewsHostableSetBounds(const gfx::Rect& bounds_in_window) = 0;
- // Called when the WebContentsView's NSView is to be hidden.
- virtual void OnViewsHostableHide() = 0;
+ // Show or hide the WebContentsView's NSView.
+ virtual void ViewsHostableSetVisible(bool visible) = 0;
- // Called when the WebContentsView's NSView is to be made a first responder.
- virtual void OnViewsHostableMakeFirstResponder() = 0;
+ // Make the WebContentsView's NSView be a first responder.
+ virtual void ViewsHostableMakeFirstResponder() = 0;
};
} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor.cc b/chromium/ui/base/cursor/cursor.cc
index 89bafae8df2..1ed7f1b9c4f 100644
--- a/chromium/ui/base/cursor/cursor.cc
+++ b/chromium/ui/base/cursor/cursor.cc
@@ -4,6 +4,8 @@
#include "ui/base/cursor/cursor.h"
+#include "base/logging.h"
+
namespace ui {
Cursor::Cursor()
@@ -37,6 +39,15 @@ void Cursor::SetPlatformCursor(const PlatformCursor& platform) {
RefCustomCursor();
}
+#if !defined(USE_AURA)
+void Cursor::RefCustomCursor() {
+ NOTIMPLEMENTED();
+}
+void Cursor::UnrefCustomCursor() {
+ NOTIMPLEMENTED();
+}
+#endif
+
SkBitmap Cursor::GetBitmap() const {
if (native_type_ == CursorType::kCustom)
return custom_bitmap_;
@@ -57,6 +68,14 @@ gfx::Point Cursor::GetHotspot() const {
#endif
}
+bool Cursor::IsSameAs(const Cursor& rhs) const {
+ return native_type_ == rhs.native_type_ &&
+ custom_hotspot_ == rhs.custom_hotspot_ &&
+ device_scale_factor_ == rhs.device_scale_factor_ &&
+ custom_bitmap_.getGenerationID() ==
+ rhs.custom_bitmap_.getGenerationID();
+}
+
void Cursor::Assign(const Cursor& cursor) {
if (*this == cursor)
return;
diff --git a/chromium/ui/base/cursor/cursor.h b/chromium/ui/base/cursor/cursor.h
index c1348e90b60..06b5510a94b 100644
--- a/chromium/ui/base/cursor/cursor.h
+++ b/chromium/ui/base/cursor/cursor.h
@@ -87,6 +87,18 @@ class UI_BASE_EXPORT Cursor {
Assign(cursor);
}
+ // Checks if the data in |rhs| was created from the same input data.
+ //
+ // This is subtly different from operator==, as we need this to be a
+ // lightweight operation instead of performing pixel equality checks on
+ // arbitrary sized SkBitmaps. So we check the internal SkBitmap generation
+ // IDs, which are per-process, monotonically increasing ids which get changed
+ // whenever there's a modification to the pixel data. This means that this
+ // method can have false negatives: two SkBitmap instances made with the same
+ // input data (but which weren't copied from each other) can have equal pixel
+ // data, but different generation ids.
+ bool IsSameAs(const Cursor& rhs) const;
+
private:
void Assign(const Cursor& cursor);
diff --git a/chromium/ui/base/cursor/cursor_data.cc b/chromium/ui/base/cursor/cursor_data.cc
deleted file mode 100644
index 2ba8500eade..00000000000
--- a/chromium/ui/base/cursor/cursor_data.cc
+++ /dev/null
@@ -1,93 +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/cursor_data.h"
-
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/cursor/cursor_type.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
-
-#if defined(USE_OZONE)
-#include "ui/ozone/public/cursor_factory_ozone.h"
-#endif
-
-namespace ui {
-
-CursorData::CursorData()
- : cursor_type_(CursorType::kNull), scale_factor_(0.0f) {}
-
-CursorData::CursorData(CursorType type)
- : cursor_type_(type), scale_factor_(0.0f) {}
-
-CursorData::CursorData(const gfx::Point& hotspot_point,
- const std::vector<SkBitmap>& cursor_frames,
- float scale_factor,
- const base::TimeDelta& frame_delay)
- : cursor_type_(CursorType::kCustom),
- frame_delay_(frame_delay),
- scale_factor_(scale_factor),
- hotspot_(hotspot_point),
- cursor_frames_(cursor_frames) {
- for (SkBitmap& bitmap : cursor_frames_)
- generator_ids_.push_back(bitmap.getGenerationID());
-}
-
-CursorData::CursorData(const CursorData& cursor) = default;
-
-CursorData::CursorData(CursorData&& cursor) = default;
-
-CursorData::~CursorData() {}
-
-CursorData& CursorData::operator=(const CursorData& cursor) = default;
-
-CursorData& CursorData::operator=(CursorData&& cursor) = default;
-
-bool CursorData::IsType(CursorType cursor_type) const {
- return cursor_type_ == cursor_type;
-}
-
-bool CursorData::IsSameAs(const CursorData& rhs) const {
- return cursor_type_ == rhs.cursor_type_ && frame_delay_ == rhs.frame_delay_ &&
- hotspot_ == rhs.hotspot_ && scale_factor_ == rhs.scale_factor_ &&
- generator_ids_ == rhs.generator_ids_;
-}
-
-#if defined(USE_AURA)
-gfx::NativeCursor CursorData::ToNativeCursor() const {
- Cursor cursor(cursor_type_);
-
-#if defined(USE_OZONE)
- auto* factory = CursorFactoryOzone::GetInstance();
- if (cursor_type_ != CursorType::kCustom) {
- cursor.SetPlatformCursor(factory->GetDefaultCursor(cursor_type_));
- } else if (cursor_frames_.size() > 1U) {
- cursor.SetPlatformCursor(factory->CreateAnimatedCursor(
- cursor_frames_, hotspot_, frame_delay_.InMilliseconds(),
- scale_factor_));
- // CreateAnimatedCursor() and CreateImageCursor() below both return a cursor
- // with a ref count of 1, which we need to account for after storing it in
- // |cursor|.
- cursor.UnrefCustomCursor();
- } else {
- DCHECK_EQ(1U, cursor_frames_.size());
- cursor.SetPlatformCursor(
- factory->CreateImageCursor(cursor_frames_[0], hotspot_, scale_factor_));
- cursor.UnrefCustomCursor();
- }
-#else
- NOTIMPLEMENTED();
-#endif
-
- if (!cursor_frames_.empty()) {
- cursor.set_custom_bitmap(cursor_frames_[0]);
- cursor.set_custom_hotspot(hotspot_);
- }
- return cursor;
-}
-#endif
-
-} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_data.h b/chromium/ui/base/cursor/cursor_data.h
deleted file mode 100644
index ada9dd618f5..00000000000
--- a/chromium/ui/base/cursor/cursor_data.h
+++ /dev/null
@@ -1,105 +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_CURSOR_DATA_H_
-#define UI_BASE_CURSOR_CURSOR_DATA_H_
-
-#include <vector>
-
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "ui/base/ui_base_export.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/native_widget_types.h"
-
-class SkBitmap;
-
-namespace ui {
-enum class CursorType;
-
-// The new Cursor class. (aka, Cursor2)
-//
-// Contains all data for a cursor. Its type, along with any custom bitmap
-// images, hotspot data, scaling factors, etc.
-//
-// Why a new class? ui::Cursor currently wraps a PlatformCursor, which is a
-// platform specific representation, which is generated in //content/. This
-// previously was OK, as a WebCursor was sent over chrome IPC from the renderer
-// to the browser process, and then the data in WebCursor was turned into the
-// an opaque platform specific structure, stuffed inside ui::Cursor, and then
-// read by win32 or x11. Now, the windowing server can be in a separate
-// process, so this doesn't work.
-//
-// Using a raw mojo struct is not convenient; we want to have copyable classes
-// which are internally copy-on-write for large data, like the internally used
-// SkBitmap, as we cache this data at multiple layers.
-//
-// TODO(erg): Rename this to ui::Cursor once we've mojoified the entire chain
-// from the renderer to the window server.
-class UI_BASE_EXPORT CursorData {
- public:
- CursorData();
- explicit CursorData(CursorType type);
- CursorData(const gfx::Point& hostpot_point,
- const std::vector<SkBitmap>& cursor_frames,
- float scale_factor,
- const base::TimeDelta& frame_delay);
- CursorData(const CursorData& cursor);
- CursorData(CursorData&& cursor);
- ~CursorData();
-
- CursorData& operator=(const CursorData& cursor);
- CursorData& operator=(CursorData&& cursor);
-
- CursorType cursor_type() const { return cursor_type_; }
- const base::TimeDelta& frame_delay() const { return frame_delay_; }
- float scale_factor() const { return scale_factor_; }
- const gfx::Point& hotspot_in_pixels() const { return hotspot_; }
- const std::vector<SkBitmap>& cursor_frames() const { return cursor_frames_; }
-
- // Returns true if this CursorData instance is of |cursor_type|.
- bool IsType(CursorType cursor_type) const;
-
- // Checks if the data in |rhs| was created from the same input data.
- //
- // This is subtly different from operator==, as we need this to be a
- // lightweight operation instead of performing pixel equality checks on
- // arbitrary sized SkBitmaps. So we check the internal SkBitmap generation
- // IDs, which are per-process, monotonically increasing ids which get changed
- // whenever there's a modification to the pixel data. This means that this
- // method can have false negatives: two SkBitmap instances made with the same
- // input data (but which weren't copied from each other) can have equal pixel
- // data, but different generation ids.
- bool IsSameAs(const CursorData& rhs) const;
-
- // Until CursorData replaces Cursor, it's necessary to convert back to Cursor.
- // Some code such as CursorWindowController still uses Cursor (and not its
- // PlatformCursor).
- gfx::NativeCursor ToNativeCursor() const;
-
- private:
- // A native type constant from cursor.h.
- CursorType cursor_type_;
-
- // The delay between cursor frames.
- base::TimeDelta frame_delay_;
-
- // The scale factor of the images in |cursor_frames_|.
- float scale_factor_;
-
- // The hotspot in cursor frames.
- gfx::Point hotspot_;
-
- // The frames of a cursor.
- std::vector<SkBitmap> cursor_frames_;
-
- // Generator IDs. The size of |generator_ids_| must be equal to the size of
- // cursor_frames_, and is generated when we set the bitmaps. We produce these
- // unique IDs so we can do quick equality checks.
- std::vector<uint32_t> generator_ids_;
-};
-
-} // namespace ui
-
-#endif // UI_BASE_CURSOR_CURSOR_DATA_H_
diff --git a/chromium/ui/base/cursor/cursor_util.cc b/chromium/ui/base/cursor/cursor_util.cc
index 3735bf69664..caca9287107 100644
--- a/chromium/ui/base/cursor/cursor_util.cc
+++ b/chromium/ui/base/cursor/cursor_util.cc
@@ -5,7 +5,6 @@
#include "ui/base/cursor/cursor_util.h"
#include "base/logging.h"
-#include "skia/ext/image_operations.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -39,7 +38,7 @@ bool ConvertSkBitmapAlphaType(SkBitmap* bitmap, SkAlphaType alpha_type) {
return true;
}
-} // namespace
+} // namespace
void ScaleAndRotateCursorBitmapAndHotpoint(float scale,
display::Display::Rotation rotation,
@@ -90,11 +89,17 @@ void ScaleAndRotateCursorBitmapAndHotpoint(float scale,
gfx::Size scaled_size = gfx::ScaleToFlooredSize(
gfx::Size(bitmap->width(), bitmap->height()), scale);
- *bitmap = skia::ImageOperations::Resize(
- *bitmap,
- skia::ImageOperations::RESIZE_BETTER,
- scaled_size.width(),
- scaled_size.height());
+ // TODO(crbug.com/919866): skia::ImageOperations::Resize() doesn't support
+ // unpremultiplied alpha bitmaps.
+ SkBitmap scaled_bitmap;
+ scaled_bitmap.setInfo(
+ bitmap->info().makeWH(scaled_size.width(), scaled_size.height()));
+ if (scaled_bitmap.tryAllocPixels()) {
+ bitmap->pixmap().scalePixels(scaled_bitmap.pixmap(),
+ kMedium_SkFilterQuality);
+ }
+
+ *bitmap = scaled_bitmap;
*hotpoint = gfx::ScaleToFlooredPoint(*hotpoint, scale);
}
diff --git a/chromium/ui/base/cursor/cursor_loader_x11_unittest.cc b/chromium/ui/base/cursor/cursor_util_unittest.cc
index b1e393e8f0a..360f7fabf5c 100644
--- a/chromium/ui/base/cursor/cursor_loader_x11_unittest.cc
+++ b/chromium/ui/base/cursor/cursor_util_unittest.cc
@@ -1,48 +1,70 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/cursor/cursor_loader_x11.h"
+#include "ui/base/cursor/cursor_util.h"
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/cursor/cursor_util.h"
-#include "ui/display/display.h"
namespace ui {
+namespace {
+
+// Parameterized test for cursor bitmaps with premultiplied and unpremultiplied
+// alpha.
+class CursorUtilTest : public testing::TestWithParam<bool> {
+ public:
+ SkColor GetPixelColor() {
+ return GetParam() ? SkColorSetARGB(128, 255, 0, 0)
+ : SkColorSetARGB(128, 128, 0, 0);
+ }
+ SkImageInfo GetImageInfo() {
+ return GetParam() ? SkImageInfo::MakeN32(10, 5, kUnpremul_SkAlphaType)
+ : SkImageInfo::MakeN32(10, 5, kPremul_SkAlphaType);
+ }
+};
+
+TEST_P(CursorUtilTest, ScaleAndRotate) {
+ const SkColor pixel_color = GetPixelColor();
-TEST(CursorLoaderX11Test, ScaleAndRotate) {
SkBitmap bitmap;
- bitmap.allocN32Pixels(10, 5);
- bitmap.eraseColor(SK_ColorBLACK);
+ bitmap.setInfo(GetImageInfo());
+ bitmap.allocPixels();
+ bitmap.eraseColor(pixel_color);
- gfx::Point hotpoint(3,4);
+ gfx::Point hotpoint(3, 4);
ScaleAndRotateCursorBitmapAndHotpoint(1.0f, display::Display::ROTATE_0,
&bitmap, &hotpoint);
EXPECT_EQ(10, bitmap.width());
EXPECT_EQ(5, bitmap.height());
EXPECT_EQ("3,4", hotpoint.ToString());
+ EXPECT_EQ(pixel_color, bitmap.pixmap().getColor(0, 0));
ScaleAndRotateCursorBitmapAndHotpoint(1.0f, display::Display::ROTATE_90,
&bitmap, &hotpoint);
-
EXPECT_EQ(5, bitmap.width());
EXPECT_EQ(10, bitmap.height());
EXPECT_EQ("1,3", hotpoint.ToString());
+ EXPECT_EQ(pixel_color, bitmap.pixmap().getColor(0, 0));
ScaleAndRotateCursorBitmapAndHotpoint(2.0f, display::Display::ROTATE_180,
&bitmap, &hotpoint);
EXPECT_EQ(10, bitmap.width());
EXPECT_EQ(20, bitmap.height());
EXPECT_EQ("8,14", hotpoint.ToString());
+ EXPECT_EQ(pixel_color, bitmap.pixmap().getColor(0, 0));
ScaleAndRotateCursorBitmapAndHotpoint(1.0f, display::Display::ROTATE_270,
&bitmap, &hotpoint);
EXPECT_EQ(20, bitmap.width());
EXPECT_EQ(10, bitmap.height());
EXPECT_EQ("14,2", hotpoint.ToString());
+ EXPECT_EQ(pixel_color, bitmap.pixmap().getColor(0, 0));
}
+INSTANTIATE_TEST_CASE_P(, CursorUtilTest, testing::Bool());
+
+} // namespace
} // namespace ui
diff --git a/chromium/ui/base/cursor/cursors_aura.cc b/chromium/ui/base/cursor/cursors_aura.cc
index 1ceda419b17..63a5d5361a8 100644
--- a/chromium/ui/base/cursor/cursors_aura.cc
+++ b/chromium/ui/base/cursor/cursors_aura.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/resource/resource_bundle.h"
@@ -204,16 +204,16 @@ const CursorData kAnimatedCursors[] = {
};
const CursorSizeData kCursorSizes[] = {
- {CursorSize::kNormal, kNormalCursors, arraysize(kNormalCursors),
- kAnimatedCursors, arraysize(kAnimatedCursors)},
- {CursorSize::kLarge, kLargeCursors, arraysize(kLargeCursors),
+ {CursorSize::kNormal, kNormalCursors, base::size(kNormalCursors),
+ kAnimatedCursors, base::size(kAnimatedCursors)},
+ {CursorSize::kLarge, kLargeCursors, base::size(kLargeCursors),
// TODO(yoshiki): Replace animated cursors with big assets.
// crbug.com/247254
- kAnimatedCursors, arraysize(kAnimatedCursors)},
+ kAnimatedCursors, base::size(kAnimatedCursors)},
};
const CursorSizeData* GetCursorSizeByType(CursorSize cursor_size) {
- for (size_t i = 0; i < arraysize(kCursorSizes); ++i) {
+ for (size_t i = 0; i < base::size(kCursorSizes); ++i) {
if (kCursorSizes[i].id == cursor_size)
return &kCursorSizes[i];
}
diff --git a/chromium/ui/base/cursor/image_cursors.cc b/chromium/ui/base/cursor/image_cursors.cc
index 435fa5a0675..f41fcf9e7ba 100644
--- a/chromium/ui/base/cursor/image_cursors.cc
+++ b/chromium/ui/base/cursor/image_cursors.cc
@@ -8,7 +8,7 @@
#include <stddef.h>
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/cursor_loader.h"
@@ -111,7 +111,7 @@ void ImageCursors::ReloadCursors() {
cursor_loader_->UnloadAll();
- for (size_t i = 0; i < arraysize(kImageCursorIds); ++i) {
+ for (size_t i = 0; i < base::size(kImageCursorIds); ++i) {
int resource_id = -1;
gfx::Point hot_point;
bool success =
@@ -120,7 +120,7 @@ void ImageCursors::ReloadCursors() {
DCHECK(success);
cursor_loader_->LoadImageCursor(kImageCursorIds[i], resource_id, hot_point);
}
- for (size_t i = 0; i < arraysize(kAnimatedCursorIds); ++i) {
+ for (size_t i = 0; i < base::size(kAnimatedCursorIds); ++i) {
int resource_id = -1;
gfx::Point hot_point;
bool success =
diff --git a/chromium/ui/base/dragdrop/os_exchange_data.cc b/chromium/ui/base/dragdrop/os_exchange_data.cc
index bae9df1a8bb..11cf7dbe66d 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data.cc
@@ -6,6 +6,7 @@
#include "base/pickle.h"
#include "build/build_config.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
#include "url/gurl.h"
@@ -56,7 +57,7 @@ void OSExchangeData::SetFilenames(
provider_->SetFilenames(filenames);
}
-void OSExchangeData::SetPickledData(const Clipboard::FormatType& format,
+void OSExchangeData::SetPickledData(const ClipboardFormatType& format,
const base::Pickle& data) {
provider_->SetPickledData(format, data);
}
@@ -79,7 +80,7 @@ bool OSExchangeData::GetFilenames(std::vector<FileInfo>* filenames) const {
return provider_->GetFilenames(filenames);
}
-bool OSExchangeData::GetPickledData(const Clipboard::FormatType& format,
+bool OSExchangeData::GetPickledData(const ClipboardFormatType& format,
base::Pickle* data) const {
return provider_->GetPickledData(format, data);
}
@@ -96,14 +97,13 @@ bool OSExchangeData::HasFile() const {
return provider_->HasFile();
}
-bool OSExchangeData::HasCustomFormat(
- const Clipboard::FormatType& format) const {
+bool OSExchangeData::HasCustomFormat(const ClipboardFormatType& format) const {
return provider_->HasCustomFormat(format);
}
bool OSExchangeData::HasAnyFormat(
int formats,
- const std::set<Clipboard::FormatType>& format_types) const {
+ const std::set<ClipboardFormatType>& format_types) const {
if ((formats & STRING) != 0 && HasString())
return true;
if ((formats & URL) != 0 && HasURL(CONVERT_FILENAMES))
diff --git a/chromium/ui/base/dragdrop/os_exchange_data.h b/chromium/ui/base/dragdrop/os_exchange_data.h
index 3bb6feffc1b..cd915154ea1 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data.h
@@ -17,7 +17,6 @@
#include "base/files/file_path.h"
#include "base/macros.h"
-#include "ui/base/clipboard/clipboard.h"
#include "ui/base/dragdrop/download_file_interface.h"
#include "ui/base/ui_base_export.h"
@@ -34,6 +33,7 @@ class Vector2d;
namespace ui {
+struct ClipboardFormatType;
struct FileInfo;
///////////////////////////////////////////////////////////////////////////////
@@ -96,7 +96,7 @@ class UI_BASE_EXPORT OSExchangeData {
virtual void SetURL(const GURL& url, const base::string16& title) = 0;
virtual void SetFilename(const base::FilePath& path) = 0;
virtual void SetFilenames(const std::vector<FileInfo>& file_names) = 0;
- virtual void SetPickledData(const Clipboard::FormatType& format,
+ virtual void SetPickledData(const ClipboardFormatType& format,
const base::Pickle& data) = 0;
virtual bool GetString(base::string16* data) const = 0;
@@ -105,13 +105,13 @@ class UI_BASE_EXPORT OSExchangeData {
base::string16* title) const = 0;
virtual bool GetFilename(base::FilePath* path) const = 0;
virtual bool GetFilenames(std::vector<FileInfo>* file_names) const = 0;
- virtual bool GetPickledData(const Clipboard::FormatType& format,
+ virtual bool GetPickledData(const ClipboardFormatType& format,
base::Pickle* data) const = 0;
virtual bool HasString() const = 0;
virtual bool HasURL(FilenameToURLPolicy policy) const = 0;
virtual bool HasFile() const = 0;
- virtual bool HasCustomFormat(const Clipboard::FormatType& format) const = 0;
+ virtual bool HasCustomFormat(const ClipboardFormatType& format) const = 0;
#if defined(USE_X11) || defined(OS_WIN)
virtual void SetFileContents(const base::FilePath& filename,
@@ -174,7 +174,7 @@ class UI_BASE_EXPORT OSExchangeData {
void SetFilenames(
const std::vector<FileInfo>& file_names);
// Adds pickled data of the specified format.
- void SetPickledData(const Clipboard::FormatType& format,
+ void SetPickledData(const ClipboardFormatType& format,
const base::Pickle& data);
// These functions retrieve data of the specified type. If data exists, the
@@ -190,7 +190,7 @@ class UI_BASE_EXPORT OSExchangeData {
// Return the path of a file, if available.
bool GetFilename(base::FilePath* path) const;
bool GetFilenames(std::vector<FileInfo>* file_names) const;
- bool GetPickledData(const Clipboard::FormatType& format,
+ bool GetPickledData(const ClipboardFormatType& format,
base::Pickle* data) const;
// Test whether or not data of certain types is present, without actually
@@ -198,12 +198,12 @@ class UI_BASE_EXPORT OSExchangeData {
bool HasString() const;
bool HasURL(FilenameToURLPolicy policy) const;
bool HasFile() const;
- bool HasCustomFormat(const Clipboard::FormatType& format) const;
+ bool HasCustomFormat(const ClipboardFormatType& format) const;
// Returns true if this OSExchangeData has data in any of the formats in
// |formats| or any custom format in |custom_formats|.
bool HasAnyFormat(int formats,
- const std::set<Clipboard::FormatType>& types) const;
+ const std::set<ClipboardFormatType>& types) const;
#if defined(OS_WIN)
// Adds the bytes of a file (CFSTR_FILECONTENTS and CFSTR_FILEDESCRIPTOR on
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc
index 200d0c88ce3..40dbe89567b 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc
@@ -8,8 +8,7 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/filename_util.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/file_info.h"
namespace ui {
@@ -75,7 +74,7 @@ void OSExchangeDataProviderAura::SetFilenames(
}
void OSExchangeDataProviderAura::SetPickledData(
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
const base::Pickle& data) {
pickle_data_[format] = data;
formats_ |= OSExchangeData::PICKLED_DATA;
@@ -123,7 +122,7 @@ bool OSExchangeDataProviderAura::GetFilenames(
}
bool OSExchangeDataProviderAura::GetPickledData(
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
base::Pickle* data) const {
PickleData::const_iterator i = pickle_data_.find(format);
if (i == pickle_data_.end())
@@ -152,7 +151,7 @@ bool OSExchangeDataProviderAura::HasFile() const {
}
bool OSExchangeDataProviderAura::HasCustomFormat(
- const Clipboard::FormatType& format) const {
+ const ClipboardFormatType& format) const {
return pickle_data_.find(format) != pickle_data_.end();
}
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h
index fe752434082..2b7cd149bfc 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h
@@ -17,7 +17,7 @@
namespace ui {
-class Clipboard;
+struct ClipboardFormatType;
// OSExchangeData::Provider implementation for aura on linux.
class UI_BASE_EXPORT OSExchangeDataProviderAura
@@ -34,7 +34,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderAura
void SetURL(const GURL& url, const base::string16& title) override;
void SetFilename(const base::FilePath& path) override;
void SetFilenames(const std::vector<FileInfo>& filenames) override;
- void SetPickledData(const Clipboard::FormatType& format,
+ void SetPickledData(const ClipboardFormatType& format,
const base::Pickle& data) override;
bool GetString(base::string16* data) const override;
bool GetURLAndTitle(OSExchangeData::FilenameToURLPolicy policy,
@@ -42,13 +42,12 @@ class UI_BASE_EXPORT OSExchangeDataProviderAura
base::string16* title) const override;
bool GetFilename(base::FilePath* path) const override;
bool GetFilenames(std::vector<FileInfo>* filenames) const override;
- bool GetPickledData(const Clipboard::FormatType& format,
+ bool GetPickledData(const ClipboardFormatType& format,
base::Pickle* data) const override;
bool HasString() const override;
bool HasURL(OSExchangeData::FilenameToURLPolicy policy) const override;
bool HasFile() const override;
- bool HasCustomFormat(const Clipboard::FormatType& format) const
- override;
+ bool HasCustomFormat(const ClipboardFormatType& format) const override;
void SetHtml(const base::string16& html, const GURL& base_url) override;
bool GetHtml(base::string16* html, GURL* base_url) const override;
@@ -59,7 +58,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderAura
gfx::Vector2d GetDragImageOffset() const override;
private:
- typedef std::map<Clipboard::FormatType, base::Pickle> PickleData;
+ typedef std::map<ClipboardFormatType, base::Pickle> PickleData;
// Returns true if |formats_| contains a file format and the file name can be
// parsed as a URL.
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 144c8babf50..c9230105516 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
@@ -12,8 +12,8 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/filename_util.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/x/selection_utils.h"
#include "ui/events/platform/platform_event_source.h"
@@ -117,7 +117,7 @@ void OSExchangeDataProviderAuraX11::SetString(const base::string16& text_data) {
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedString::TakeString(&utf8));
- format_map_.Insert(gfx::GetAtom(Clipboard::kMimeTypeText), mem);
+ format_map_.Insert(gfx::GetAtom(kMimeTypeText), mem);
format_map_.Insert(gfx::GetAtom(kText), mem);
format_map_.Insert(gfx::GetAtom(kString), mem);
format_map_.Insert(gfx::GetAtom(kUtf8String), mem);
@@ -138,7 +138,7 @@ void OSExchangeDataProviderAuraX11::SetURL(const GURL& url,
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedBytes::TakeVector(&data));
- format_map_.Insert(gfx::GetAtom(Clipboard::kMimeTypeMozillaURL), mem);
+ format_map_.Insert(gfx::GetAtom(kMimeTypeMozillaURL), mem);
// Set a string fallback as well.
SetString(spec);
@@ -182,11 +182,11 @@ void OSExchangeDataProviderAuraX11::SetFilenames(
std::string joined_data = base::JoinString(paths, "\n");
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedString::TakeString(&joined_data));
- format_map_.Insert(gfx::GetAtom(Clipboard::kMimeTypeURIList), mem);
+ format_map_.Insert(gfx::GetAtom(kMimeTypeURIList), mem);
}
void OSExchangeDataProviderAuraX11::SetPickledData(
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
const base::Pickle& pickle) {
const unsigned char* data =
reinterpret_cast<const unsigned char*>(pickle.data());
@@ -235,7 +235,7 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
// but that doesn't match the assumptions of the rest of the system which
// expect single types.
- if (data.GetType() == gfx::GetAtom(Clipboard::kMimeTypeMozillaURL)) {
+ if (data.GetType() == gfx::GetAtom(kMimeTypeMozillaURL)) {
// Mozilla URLs are (UTF16: URL, newline, title).
base::string16 unparsed;
data.AssignTo(&unparsed);
@@ -252,7 +252,7 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
*url = GURL(tokens[0]);
return true;
}
- } else if (data.GetType() == gfx::GetAtom(Clipboard::kMimeTypeURIList)) {
+ } else if (data.GetType() == gfx::GetAtom(kMimeTypeURIList)) {
std::vector<std::string> tokens = ui::ParseURIList(data);
for (const std::string& token : tokens) {
GURL test_url(token);
@@ -302,7 +302,7 @@ bool OSExchangeDataProviderAuraX11::GetFilenames(
}
bool OSExchangeDataProviderAuraX11::GetPickledData(
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
base::Pickle* pickle) const {
std::vector< ::Atom> requested_types;
requested_types.push_back(gfx::GetAtom(format.ToString().c_str()));
@@ -339,11 +339,10 @@ bool OSExchangeDataProviderAuraX11::HasURL(
// Windows does and stuffs all the data into one mime type.
ui::SelectionData data(format_map_.GetFirstOf(requested_types));
if (data.IsValid()) {
- if (data.GetType() == gfx::GetAtom(Clipboard::kMimeTypeMozillaURL)) {
+ if (data.GetType() == gfx::GetAtom(kMimeTypeMozillaURL)) {
// File managers shouldn't be using this type, so this is a URL.
return true;
- } else if (data.GetType() ==
- gfx::GetAtom(ui::Clipboard::kMimeTypeURIList)) {
+ } else if (data.GetType() == gfx::GetAtom(ui::kMimeTypeURIList)) {
std::vector<std::string> tokens = ui::ParseURIList(data);
for (const std::string& token : tokens) {
if (!GURL(token).SchemeIsFile() ||
@@ -384,7 +383,7 @@ bool OSExchangeDataProviderAuraX11::HasFile() const {
}
bool OSExchangeDataProviderAuraX11::HasCustomFormat(
- const Clipboard::FormatType& format) const {
+ const ClipboardFormatType& format) const {
std::vector< ::Atom> url_atoms;
url_atoms.push_back(gfx::GetAtom(format.ToString().c_str()));
std::vector< ::Atom> requested_types;
@@ -398,7 +397,7 @@ void OSExchangeDataProviderAuraX11::SetFileContents(
const std::string& file_contents) {
DCHECK(!filename.empty());
DCHECK(format_map_.end() ==
- format_map_.find(gfx::GetAtom(Clipboard::kMimeTypeMozillaURL)));
+ format_map_.find(gfx::GetAtom(kMimeTypeMozillaURL)));
file_contents_name_ = filename;
@@ -439,13 +438,13 @@ void OSExchangeDataProviderAuraX11::SetHtml(const base::string16& html,
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedBytes::TakeVector(&bytes));
- format_map_.Insert(gfx::GetAtom(Clipboard::kMimeTypeHTML), mem);
+ format_map_.Insert(gfx::GetAtom(kMimeTypeHTML), mem);
}
bool OSExchangeDataProviderAuraX11::GetHtml(base::string16* html,
GURL* base_url) const {
std::vector< ::Atom> url_atoms;
- url_atoms.push_back(gfx::GetAtom(Clipboard::kMimeTypeHTML));
+ url_atoms.push_back(gfx::GetAtom(kMimeTypeHTML));
std::vector< ::Atom> requested_types;
GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
@@ -461,7 +460,7 @@ bool OSExchangeDataProviderAuraX11::GetHtml(base::string16* html,
bool OSExchangeDataProviderAuraX11::HasHtml() const {
std::vector< ::Atom> url_atoms;
- url_atoms.push_back(gfx::GetAtom(Clipboard::kMimeTypeHTML));
+ url_atoms.push_back(gfx::GetAtom(kMimeTypeHTML));
std::vector< ::Atom> requested_types;
GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h
index f8e60b31ac6..b1106d929b3 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h
@@ -23,7 +23,6 @@
namespace ui {
-class Clipboard;
class OSExchangeDataProviderAuraX11Test;
// OSExchangeData::Provider implementation for aura on linux.
@@ -65,7 +64,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderAuraX11
void SetURL(const GURL& url, const base::string16& title) override;
void SetFilename(const base::FilePath& path) override;
void SetFilenames(const std::vector<FileInfo>& filenames) override;
- void SetPickledData(const Clipboard::FormatType& format,
+ void SetPickledData(const ClipboardFormatType& format,
const base::Pickle& pickle) override;
bool GetString(base::string16* data) const override;
bool GetURLAndTitle(OSExchangeData::FilenameToURLPolicy policy,
@@ -73,12 +72,12 @@ class UI_BASE_EXPORT OSExchangeDataProviderAuraX11
base::string16* title) const override;
bool GetFilename(base::FilePath* path) const override;
bool GetFilenames(std::vector<FileInfo>* filenames) const override;
- bool GetPickledData(const Clipboard::FormatType& format,
+ bool GetPickledData(const ClipboardFormatType& format,
base::Pickle* pickle) const override;
bool HasString() const override;
bool HasURL(OSExchangeData::FilenameToURLPolicy policy) const override;
bool HasFile() const override;
- bool HasCustomFormat(const Clipboard::FormatType& format) const override;
+ bool HasCustomFormat(const ClipboardFormatType& format) const override;
void SetFileContents(const base::FilePath& filename,
const std::string& file_contents) override;
@@ -97,7 +96,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderAuraX11
private:
friend class OSExchangeDataProviderAuraX11Test;
- typedef std::map<Clipboard::FormatType, base::Pickle> PickleData;
+ typedef std::map<ClipboardFormatType, base::Pickle> PickleData;
// Returns true if |formats_| contains a string format and the string can be
// parsed as a URL.
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc
index 9403c2a626a..ac42a4dccfa 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc
@@ -8,6 +8,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/events/platform/x11/x11_event_source_glib.h"
#include "ui/gfx/x/x11_atom_cache.h"
@@ -32,8 +33,7 @@ class OSExchangeDataProviderAuraX11Test : public testing::Test {
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedString::TakeString(&contents_copy));
- provider.format_map_.Insert(gfx::GetAtom(ui::Clipboard::kMimeTypeURIList),
- mem);
+ provider.format_map_.Insert(gfx::GetAtom(ui::kMimeTypeURIList), mem);
}
protected:
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h
index edc52f42540..5ba2a691e38 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h
@@ -35,7 +35,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderMac
void SetURL(const GURL& url, const base::string16& title) override;
void SetFilename(const base::FilePath& path) override;
void SetFilenames(const std::vector<FileInfo>& filenames) override;
- void SetPickledData(const Clipboard::FormatType& format,
+ void SetPickledData(const ClipboardFormatType& format,
const base::Pickle& data) override;
bool GetString(base::string16* data) const override;
bool GetURLAndTitle(OSExchangeData::FilenameToURLPolicy policy,
@@ -43,12 +43,12 @@ class UI_BASE_EXPORT OSExchangeDataProviderMac
base::string16* title) const override;
bool GetFilename(base::FilePath* path) const override;
bool GetFilenames(std::vector<FileInfo>* filenames) const override;
- bool GetPickledData(const Clipboard::FormatType& format,
+ bool GetPickledData(const ClipboardFormatType& format,
base::Pickle* data) const override;
bool HasString() const override;
bool HasURL(OSExchangeData::FilenameToURLPolicy policy) const override;
bool HasFile() const override;
- bool HasCustomFormat(const Clipboard::FormatType& format) const override;
+ bool HasCustomFormat(const ClipboardFormatType& format) const override;
void SetDragImage(const gfx::ImageSkia& image,
const gfx::Vector2d& cursor_offset) override;
gfx::ImageSkia GetDragImage() const override;
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 4a626b30093..68e89f0ff15 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
@@ -12,6 +12,8 @@
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#import "ui/base/clipboard/clipboard_util_mac.h"
#include "ui/base/clipboard/custom_data_helper.h"
#import "ui/base/dragdrop/cocoa_dnd_util.h"
@@ -78,7 +80,7 @@ void OSExchangeDataProviderMac::SetFilenames(
}
void OSExchangeDataProviderMac::SetPickledData(
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
const base::Pickle& data) {
NSData* ns_data = [NSData dataWithBytes:data.data() length:data.size()];
[pasteboard_->get() setData:ns_data forType:format.ToNSString()];
@@ -160,7 +162,7 @@ bool OSExchangeDataProviderMac::GetFilenames(
}
bool OSExchangeDataProviderMac::GetPickledData(
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
base::Pickle* data) const {
DCHECK(data);
NSData* ns_data = [pasteboard_->get() dataForType:format.ToNSString()];
@@ -189,7 +191,7 @@ bool OSExchangeDataProviderMac::HasFile() const {
}
bool OSExchangeDataProviderMac::HasCustomFormat(
- const Clipboard::FormatType& format) const {
+ const ClipboardFormatType& format) const {
return [[pasteboard_->get() types] containsObject:format.ToNSString()];
}
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 83f6da002e8..db7425bbf14 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
@@ -17,16 +17,16 @@
#include "base/files/file_path.h"
#include "base/i18n/file_util_icu.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/pickle.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_hglobal.h"
#include "net/base/filename_util.h"
#include "skia/ext/skia_utils_win.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/clipboard_util_win.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/l10n/l10n_util.h"
@@ -38,9 +38,9 @@
namespace ui {
-static const Clipboard::FormatType& GetRendererTaintFormatType() {
- static base::NoDestructor<Clipboard::FormatType> format(
- ui::Clipboard::GetFormatType("chromium/x-renderer-taint"));
+static const ClipboardFormatType& GetRendererTaintFormatType() {
+ static base::NoDestructor<ClipboardFormatType> format(
+ ui::ClipboardFormatType::GetType("chromium/x-renderer-taint"));
return *format;
}
@@ -306,12 +306,12 @@ bool OSExchangeDataProviderWin::DidOriginateFromRenderer() const {
void OSExchangeDataProviderWin::SetString(const base::string16& data) {
STGMEDIUM* storage = GetStorageForString(data);
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetPlainTextWFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetPlainTextWType().ToFormatEtc(), storage));
// Also add the UTF8-encoded version.
storage = GetStorageForString(base::UTF16ToUTF8(data));
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetPlainTextFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetPlainTextType().ToFormatEtc(), storage));
}
void OSExchangeDataProviderWin::SetURL(const GURL& url,
@@ -328,7 +328,7 @@ void OSExchangeDataProviderWin::SetURL(const GURL& url,
x_moz_url_str += title;
STGMEDIUM* storage = GetStorageForString(x_moz_url_str);
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetMozUrlFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetMozUrlType().ToFormatEtc(), storage));
// Add a .URL shortcut file for dragging to Explorer.
base::string16 valid_file_name;
@@ -340,10 +340,10 @@ void OSExchangeDataProviderWin::SetURL(const GURL& url,
// Add a UniformResourceLocator link for apps like IE and Word.
storage = GetStorageForString(base::UTF8ToUTF16(url.spec()));
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetUrlWFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetUrlWType().ToFormatEtc(), storage));
storage = GetStorageForString(url.spec());
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetUrlFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetUrlType().ToFormatEtc(), storage));
// TODO(beng): add CF_HTML.
// http://code.google.com/p/chromium/issues/detail?id=6767GetIDListStorageForFileName
@@ -360,7 +360,7 @@ void OSExchangeDataProviderWin::SetFilename(const base::FilePath& path) {
if (!storage)
return;
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetIDListFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetIDListType().ToFormatEtc(), storage));
}
void OSExchangeDataProviderWin::SetFilenames(
@@ -370,11 +370,11 @@ void OSExchangeDataProviderWin::SetFilenames(
return;
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetCFHDropFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetCFHDropType().ToFormatEtc(), storage));
}
void OSExchangeDataProviderWin::SetPickledData(
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
const base::Pickle& data) {
STGMEDIUM* storage = GetStorageForBytes(data.data(), data.size());
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
@@ -387,12 +387,12 @@ void OSExchangeDataProviderWin::SetFileContents(
// Add CFSTR_FILEDESCRIPTOR
STGMEDIUM* storage = GetStorageForFileDescriptor(filename);
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetFileDescriptorFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetFileDescriptorType().ToFormatEtc(), storage));
// Add CFSTR_FILECONTENTS
storage = GetStorageForBytes(file_contents.data(), file_contents.length());
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetFileContentZeroFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetFileContentZeroType().ToFormatEtc(), storage));
}
void OSExchangeDataProviderWin::SetHtml(const base::string16& html,
@@ -404,12 +404,12 @@ void OSExchangeDataProviderWin::SetHtml(const base::string16& html,
std::string cf_html = ClipboardUtil::HtmlToCFHtml(utf8_html, url);
STGMEDIUM* storage = GetStorageForBytes(cf_html.c_str(), cf_html.size());
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetHtmlFormatType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetHtmlType().ToFormatEtc(), storage));
STGMEDIUM* storage_plain = GetStorageForBytes(utf8_html.c_str(),
utf8_html.size());
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetTextHtmlFormatType().ToFormatEtc(), storage_plain));
+ ClipboardFormatType::GetTextHtmlType().ToFormatEtc(), storage_plain));
}
bool OSExchangeDataProviderWin::GetString(base::string16* data) const {
@@ -459,7 +459,7 @@ bool OSExchangeDataProviderWin::GetFilenames(
}
bool OSExchangeDataProviderWin::GetPickledData(
- const Clipboard::FormatType& format,
+ const ClipboardFormatType& format,
base::Pickle* data) const {
DCHECK(data);
bool success = false;
@@ -523,7 +523,7 @@ bool OSExchangeDataProviderWin::HasHtml() const {
}
bool OSExchangeDataProviderWin::HasCustomFormat(
- const Clipboard::FormatType& format) const {
+ const ClipboardFormatType& format) const {
FORMATETC format_etc = format.ToFormatEtc();
return (source_object_->QueryGetData(&format_etc) == S_OK);
}
@@ -540,7 +540,7 @@ void OSExchangeDataProviderWin::SetDownloadFileInfo(
// Add CF_HDROP.
auto info = std::make_unique<DataObjectImpl::StoredDataInfo>(
- Clipboard::GetCFHDropFormatType().ToFormatEtc(), storage);
+ ClipboardFormatType::GetCFHDropType().ToFormatEtc(), storage);
info->downloader = download.downloader;
data_->contents_.push_back(std::move(info));
@@ -1000,7 +1000,7 @@ static void CreateValidFileNameFromTitle(const GURL& url,
base::i18n::ReplaceIllegalCharactersInPath(validated, '-');
}
static const wchar_t extension[] = L".url";
- static const size_t max_length = MAX_PATH - arraysize(extension);
+ static const size_t max_length = MAX_PATH - base::size(extension);
if (validated->size() > max_length)
validated->erase(max_length);
*validated += extension;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h
index a47c93b1f6a..96fa77ec763 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h
@@ -154,7 +154,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderWin
void SetURL(const GURL& url, const base::string16& title) override;
void SetFilename(const base::FilePath& path) override;
void SetFilenames(const std::vector<FileInfo>& filenames) override;
- void SetPickledData(const Clipboard::FormatType& format,
+ void SetPickledData(const ClipboardFormatType& format,
const base::Pickle& data) override;
void SetFileContents(const base::FilePath& filename,
const std::string& file_contents) override;
@@ -166,7 +166,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderWin
base::string16* title) const override;
bool GetFilename(base::FilePath* path) const override;
bool GetFilenames(std::vector<FileInfo>* filenames) const override;
- bool GetPickledData(const Clipboard::FormatType& format,
+ bool GetPickledData(const ClipboardFormatType& format,
base::Pickle* data) const override;
bool GetFileContents(base::FilePath* filename,
std::string* file_contents) const override;
@@ -176,7 +176,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderWin
bool HasFile() const override;
bool HasFileContents() const override;
bool HasHtml() const override;
- bool HasCustomFormat(const Clipboard::FormatType& format) const override;
+ bool HasCustomFormat(const ClipboardFormatType& format) const override;
void SetDownloadFileInfo(
const OSExchangeData::DownloadFileInfo& download_info) override;
void SetDragImage(const gfx::ImageSkia& image_skia,
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
index 9291ca57f51..93e8ed6a0e4 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
@@ -12,6 +12,7 @@
#include "net/base/filename_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/events/platform/platform_event_source.h"
@@ -142,8 +143,8 @@ TEST_F(OSExchangeDataTest, TestFileToURLConversion) {
}
TEST_F(OSExchangeDataTest, TestPickledData) {
- const Clipboard::FormatType kTestFormat =
- Clipboard::GetFormatType("application/vnd.chromium.test");
+ const ui::ClipboardFormatType kTestFormat =
+ ui::ClipboardFormatType::GetType("application/vnd.chromium.test");
base::Pickle saved_pickle;
saved_pickle.WriteInt(1);
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
index 09bf9b0d6a3..161c2519a9b 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
@@ -10,7 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_hglobal.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#include "url/gurl.h"
@@ -322,7 +322,7 @@ TEST(OSExchangeDataWinTest, CFHtml) {
expected_cf_html += base::WideToUTF8(html);
expected_cf_html.append("<!--EndFragment-->\r\n</body>\r\n</html>");
- FORMATETC format = Clipboard::GetHtmlFormatType().ToFormatEtc();
+ FORMATETC format = ClipboardFormatType::GetHtmlType().ToFormatEtc();
STGMEDIUM medium;
IDataObject* data_object = OSExchangeDataProviderWin::GetIDataObject(data);
EXPECT_EQ(S_OK, data_object->GetData(&format, &medium));
diff --git a/chromium/ui/base/emoji/emoji_panel_helper_chromeos.cc b/chromium/ui/base/emoji/emoji_panel_helper_chromeos.cc
index 84ec409564a..9789028ee70 100644
--- a/chromium/ui/base/emoji/emoji_panel_helper_chromeos.cc
+++ b/chromium/ui/base/emoji/emoji_panel_helper_chromeos.cc
@@ -4,10 +4,8 @@
#include "ui/base/emoji/emoji_panel_helper.h"
-#include "base/feature_list.h"
#include "base/logging.h"
#include "base/no_destructor.h"
-#include "ui/base/ui_base_features.h"
namespace ui {
@@ -21,7 +19,9 @@ base::RepeatingClosure& GetShowEmojiKeyboardCallback() {
} // namespace
bool IsEmojiPanelSupported() {
- return base::FeatureList::IsEnabled(features::kEnableEmojiContextMenu);
+ // TODO(https://crbug.com/887649): Emoji callback is null in Mojo apps because
+ // they are in a different process. Fix it and remove the null check.
+ return !GetShowEmojiKeyboardCallback().is_null();
}
void ShowEmojiPanel() {
diff --git a/chromium/ui/base/emoji/emoji_panel_helper_mac.mm b/chromium/ui/base/emoji/emoji_panel_helper_mac.mm
index d322ea53f15..b743154699a 100644
--- a/chromium/ui/base/emoji/emoji_panel_helper_mac.mm
+++ b/chromium/ui/base/emoji/emoji_panel_helper_mac.mm
@@ -7,12 +7,11 @@
#import <Cocoa/Cocoa.h>
#include "base/feature_list.h"
-#include "ui/base/ui_base_features.h"
namespace ui {
bool IsEmojiPanelSupported() {
- return base::FeatureList::IsEnabled(features::kEnableEmojiContextMenu);
+ return true;
}
void ShowEmojiPanel() {
diff --git a/chromium/ui/base/emoji/emoji_panel_helper_win.cc b/chromium/ui/base/emoji/emoji_panel_helper_win.cc
index 23124db16d1..a4b1eca7ea3 100644
--- a/chromium/ui/base/emoji/emoji_panel_helper_win.cc
+++ b/chromium/ui/base/emoji/emoji_panel_helper_win.cc
@@ -6,18 +6,15 @@
#include <windows.h>
-#include "base/feature_list.h"
#include "base/win/windows_version.h"
-#include "ui/base/ui_base_features.h"
#include "ui/events/keycodes/keyboard_code_conversion_win.h"
namespace ui {
bool IsEmojiPanelSupported() {
- return base::FeatureList::IsEnabled(features::kEnableEmojiContextMenu) &&
- // Emoji picker is supported on Windows 10's Spring 2018 Update and
- // above.
- base::win::GetVersion() >= base::win::Version::VERSION_WIN10_RS4;
+ // Emoji picker is supported on Windows 10's Spring 2018 Update and
+ // above.
+ return base::win::GetVersion() >= base::win::Version::VERSION_WIN10_RS4;
}
void ShowEmojiPanel() {
diff --git a/chromium/ui/base/idle/idle.cc b/chromium/ui/base/idle/idle.cc
index 67432e075f1..0333fbc18ce 100644
--- a/chromium/ui/base/idle/idle.cc
+++ b/chromium/ui/base/idle/idle.cc
@@ -4,31 +4,16 @@
#include "ui/base/idle/idle.h"
-#include "base/bind.h"
-
namespace ui {
-namespace {
-
-void CalculateIdleStateCallback(int idle_threshold,
- IdleCallback notify,
- int idle_time) {
- if (idle_time >= idle_threshold)
- notify.Run(IDLE_STATE_IDLE);
- else
- notify.Run(IDLE_STATE_ACTIVE);
-}
-} // namespace
+IdleState CalculateIdleState(int idle_threshold) {
+ if (CheckIdleStateIsLocked())
+ return IDLE_STATE_LOCKED;
-void CalculateIdleState(int idle_threshold, IdleCallback notify) {
- if (CheckIdleStateIsLocked()) {
- notify.Run(IDLE_STATE_LOCKED);
- return;
- }
+ if (CalculateIdleTime() >= idle_threshold)
+ return IDLE_STATE_IDLE;
- CalculateIdleTime(base::Bind(&CalculateIdleStateCallback,
- idle_threshold,
- notify));
+ return IDLE_STATE_ACTIVE;
}
} // namespace ui
diff --git a/chromium/ui/base/idle/idle.h b/chromium/ui/base/idle/idle.h
index 9ea9f439fb8..269ca44c942 100644
--- a/chromium/ui/base/idle/idle.h
+++ b/chromium/ui/base/idle/idle.h
@@ -5,7 +5,6 @@
#ifndef UI_BASE_IDLE_IDLE_H_
#define UI_BASE_IDLE_IDLE_H_
-#include "base/callback.h"
#include "build/build_config.h"
#include "ui/base/ui_base_export.h"
@@ -24,16 +23,12 @@ enum IdleState {
UI_BASE_EXPORT void InitIdleMonitor();
#endif
-typedef base::Callback<void(IdleState)> IdleCallback;
-typedef base::Callback<void(int)> IdleTimeCallback;
+// Calculate the Idle state. |idle_threshold| is the amount of time (in seconds)
+// before the user is considered idle.
+UI_BASE_EXPORT IdleState CalculateIdleState(int idle_threshold);
-// Calculate the Idle state and notify the callback. |idle_threshold| is the
-// amount of time (in seconds) before considered idle. |notify| is
-// asynchronously called on some platforms.
-UI_BASE_EXPORT void CalculateIdleState(int idle_threshold, IdleCallback notify);
-
-// Calculate Idle time in seconds and notify the callback
-UI_BASE_EXPORT void CalculateIdleTime(IdleTimeCallback notify);
+// Calculate Idle time in seconds.
+UI_BASE_EXPORT int CalculateIdleTime();
// Checks synchronously if Idle state is IDLE_STATE_LOCKED.
UI_BASE_EXPORT bool CheckIdleStateIsLocked();
diff --git a/chromium/ui/base/idle/idle_android.cc b/chromium/ui/base/idle/idle_android.cc
new file mode 100644
index 00000000000..43e11476989
--- /dev/null
+++ b/chromium/ui/base/idle/idle_android.cc
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/idle/idle.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+int CalculateIdleTime() {
+ // TODO(crbug.com/878979): implementation pending.
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+bool CheckIdleStateIsLocked() {
+ // TODO(crbug.com/878979): implementation pending.
+ NOTIMPLEMENTED();
+ return false;
+}
+
+IdleState CalculateIdleState(int idle_threshold) {
+ // TODO(crbug.com/878979): implementation pending.
+ NOTIMPLEMENTED();
+ return IdleState::IDLE_STATE_UNKNOWN;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/idle/idle_chromeos.cc b/chromium/ui/base/idle/idle_chromeos.cc
index 0a382849b79..55b96ea0f61 100644
--- a/chromium/ui/base/idle/idle_chromeos.cc
+++ b/chromium/ui/base/idle/idle_chromeos.cc
@@ -11,10 +11,10 @@
namespace ui {
-void CalculateIdleTime(IdleTimeCallback notify) {
+int CalculateIdleTime() {
base::TimeDelta idle_time = base::TimeTicks::Now() -
ui::UserActivityDetector::Get()->last_activity_time();
- notify.Run(static_cast<int>(idle_time.InSeconds()));
+ return static_cast<int>(idle_time.InSeconds());
}
bool CheckIdleStateIsLocked() {
diff --git a/chromium/ui/base/idle/idle_fuchsia.cc b/chromium/ui/base/idle/idle_fuchsia.cc
index ed21be8b78a..47c26ff7684 100644
--- a/chromium/ui/base/idle/idle_fuchsia.cc
+++ b/chromium/ui/base/idle/idle_fuchsia.cc
@@ -8,10 +8,10 @@
namespace ui {
-void CalculateIdleTime(IdleTimeCallback notify) {
+int CalculateIdleTime() {
// TODO(fuchsia): https://crbug.com/743296.
NOTIMPLEMENTED();
- notify.Run(0);
+ return 0;
}
bool CheckIdleStateIsLocked() {
diff --git a/chromium/ui/base/idle/idle_linux.cc b/chromium/ui/base/idle/idle_linux.cc
index a35aca72ee9..7058b873b82 100644
--- a/chromium/ui/base/idle/idle_linux.cc
+++ b/chromium/ui/base/idle/idle_linux.cc
@@ -4,7 +4,6 @@
#include "ui/base/idle/idle.h"
-
#if defined(USE_X11)
#include "ui/base/idle/idle_query_x11.h"
#include "ui/base/idle/screensaver_window_finder_x11.h"
@@ -12,10 +11,12 @@
namespace ui {
-void CalculateIdleTime(IdleTimeCallback notify) {
+int CalculateIdleTime() {
#if defined(USE_X11)
IdleQueryX11 idle_query;
- notify.Run(idle_query.IdleTime());
+ return idle_query.IdleTime();
+#else
+ return 0;
#endif
}
diff --git a/chromium/ui/base/idle/idle_mac.mm b/chromium/ui/base/idle/idle_mac.mm
index 65d7a1ce0d8..dc355502c7c 100644
--- a/chromium/ui/base/idle/idle_mac.mm
+++ b/chromium/ui/base/idle/idle_mac.mm
@@ -84,11 +84,11 @@ void InitIdleMonitor() {
g_screenMonitor = [[MacScreenMonitor alloc] init];
}
-void CalculateIdleTime(IdleTimeCallback notify) {
+int CalculateIdleTime() {
CFTimeInterval idle_time = CGEventSourceSecondsSinceLastEventType(
kCGEventSourceStateCombinedSessionState,
kCGAnyInputEventType);
- notify.Run(static_cast<int>(idle_time));
+ return static_cast<int>(idle_time);
}
bool CheckIdleStateIsLocked() {
diff --git a/chromium/ui/base/idle/idle_win.cc b/chromium/ui/base/idle/idle_win.cc
index f151537477d..4946406f2f5 100644
--- a/chromium/ui/base/idle/idle_win.cc
+++ b/chromium/ui/base/idle/idle_win.cc
@@ -46,8 +46,8 @@ bool IsScreensaverRunning() {
} // namespace
-void CalculateIdleTime(IdleTimeCallback notify) {
- notify.Run(static_cast<int>(CalculateIdleTimeInternal()));
+int CalculateIdleTime() {
+ return static_cast<int>(CalculateIdleTimeInternal());
}
bool CheckIdleStateIsLocked() {
diff --git a/chromium/ui/base/ime/BUILD.gn b/chromium/ui/base/ime/BUILD.gn
index df6079261fd..d686d1dbed6 100644
--- a/chromium/ui/base/ime/BUILD.gn
+++ b/chromium/ui/base/ime/BUILD.gn
@@ -3,8 +3,8 @@
# found in the LICENSE file.
import("//build/config/jumbo.gni")
-import("//build/config/linux/pangocairo/pangocairo.gni")
import("//build/config/jumbo.gni")
+import("//build/config/linux/pangocairo/pangocairo.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
@@ -143,7 +143,6 @@ jumbo_component("ime") {
"//net",
"//third_party/icu",
"//ui/base",
- "//ui/base/ime/chromeos/public/interfaces",
"//ui/display",
"//ui/events",
"//ui/gfx",
@@ -189,6 +188,7 @@ jumbo_component("ime") {
deps += [
"//chromeos",
"//services/ws/public/cpp/input_devices",
+ "//ui/base/ime/chromeos/public/interfaces",
"//ui/chromeos/strings",
"//ui/events:dom_keycode_converter",
]
@@ -245,7 +245,7 @@ jumbo_component("ime") {
]
deps += [
- "//third_party/fuchsia-sdk/sdk:input",
+ "//third_party/fuchsia-sdk/sdk:ui_input",
"//ui/events",
"//ui/events:dom_keycode_converter",
]
diff --git a/chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn b/chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn
index 625cdd4cf3f..02d27d673ae 100644
--- a/chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn
+++ b/chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn
@@ -4,8 +4,13 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+assert(is_chromeos)
+
+mojom_component("interfaces") {
sources = [
"ime_keyset.mojom",
]
+
+ macro_prefix = "UI_BASE_IME_MOJOM"
+ output_prefix = "ui_base_ime_mojom"
}
diff --git a/chromium/ui/base/ime/composition_text_util_pango_unittest.cc b/chromium/ui/base/ime/composition_text_util_pango_unittest.cc
index 26e34395208..e097575bf01 100644
--- a/chromium/ui/base/ime/composition_text_util_pango_unittest.cc
+++ b/chromium/ui/base/ime/composition_text_util_pango_unittest.cc
@@ -12,7 +12,7 @@
#include <utility>
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/composition_text.h"
@@ -118,7 +118,7 @@ void CompareImeTextSpan(const ImeTextSpan& a, const ui::ImeTextSpan& b) {
}
TEST(CompositionTextUtilPangoTest, ExtractCompositionText) {
- for (size_t i = 0; i < arraysize(kTestData); ++i) {
+ for (size_t i = 0; i < base::size(kTestData); ++i) {
const char* text = kTestData[i].text;
const AttributeInfo* attrs = kTestData[i].attrs;
SCOPED_TRACE(testing::Message() << "Testing:" << i
diff --git a/chromium/ui/base/ime/dummy_text_input_client.cc b/chromium/ui/base/ime/dummy_text_input_client.cc
index 6bb143a8583..34dfc79db8e 100644
--- a/chromium/ui/base/ime/dummy_text_input_client.cc
+++ b/chromium/ui/base/ime/dummy_text_input_client.cc
@@ -92,11 +92,12 @@ bool DummyTextInputClient::GetCompositionTextRange(gfx::Range* range) const {
return false;
}
-bool DummyTextInputClient::GetSelectionRange(gfx::Range* range) const {
+bool DummyTextInputClient::GetEditableSelectionRange(gfx::Range* range) const {
return false;
}
-bool DummyTextInputClient::SetSelectionRange(const gfx::Range& range) {
+bool DummyTextInputClient::SetEditableSelectionRange(const gfx::Range& range) {
+ selection_history_.push_back(range);
return false;
}
diff --git a/chromium/ui/base/ime/dummy_text_input_client.h b/chromium/ui/base/ime/dummy_text_input_client.h
index 458309a975d..e313b0356db 100644
--- a/chromium/ui/base/ime/dummy_text_input_client.h
+++ b/chromium/ui/base/ime/dummy_text_input_client.h
@@ -40,8 +40,8 @@ class DummyTextInputClient : public TextInputClient {
ui::TextInputClient::FocusReason GetFocusReason() const override;
bool GetTextRange(gfx::Range* range) const override;
bool GetCompositionTextRange(gfx::Range* range) const override;
- bool GetSelectionRange(gfx::Range* range) const override;
- bool SetSelectionRange(const gfx::Range& range) override;
+ bool GetEditableSelectionRange(gfx::Range* range) const override;
+ bool SetEditableSelectionRange(const gfx::Range& range) override;
bool DeleteRange(const gfx::Range& range) override;
bool GetTextFromRange(const gfx::Range& range,
base::string16* text) const override;
@@ -63,6 +63,9 @@ class DummyTextInputClient : public TextInputClient {
const std::vector<CompositionText>& composition_history() const {
return composition_history_;
}
+ const std::vector<gfx::Range>& selection_history() const {
+ return selection_history_;
+ }
TextInputType text_input_type_;
TextInputMode text_input_mode_;
@@ -74,6 +77,7 @@ class DummyTextInputClient : public TextInputClient {
base::char16 last_insert_char_;
std::vector<base::string16> insert_text_history_;
std::vector<CompositionText> composition_history_;
+ std::vector<gfx::Range> selection_history_;
};
} // namespace ui
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 3f268bc0144..37938224c34 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
@@ -7,31 +7,26 @@
#include <utility>
#include "base/fuchsia/component_context.h"
+#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/events/base_event_utils.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/events/keycodes/dom/keycode_converter.h"
namespace ui {
InputMethodKeyboardControllerFuchsia::InputMethodKeyboardControllerFuchsia(
- InputMethodFuchsia* input_method)
- : event_converter_(input_method),
- ime_client_binding_(this),
- ime_service_(base::fuchsia::ComponentContext::GetDefault()
- ->ConnectToService<fuchsia::ui::input::ImeService>()),
+ fuchsia::ui::input::ImeService* ime_service)
+ : ime_service_(ime_service),
ime_visibility_(
base::fuchsia::ComponentContext::GetDefault()
- ->ConnectToService<fuchsia::ui::input::ImeVisibilityService>()),
- input_method_(input_method) {
+ ->ConnectToService<fuchsia::ui::input::ImeVisibilityService>()) {
DCHECK(ime_service_);
- DCHECK(input_method_);
- ime_service_.set_error_handler([this](zx_status_t status) {
- LOG(ERROR) << "Lost connection to IME service.";
- ime_.Unbind();
- ime_client_binding_.Unbind();
+ ime_visibility_.set_error_handler([this](zx_status_t status) {
+ ZX_LOG(WARNING, status) << "ImeVisibilityService connection lost.";
+
+ // We can't observe visibility events anymore, so dismiss the keyboard and
+ // assume that it's closed for good.
+ DismissVirtualKeyboard();
+ keyboard_visible_ = false;
});
ime_visibility_.events().OnKeyboardVisibilityChanged = [this](bool visible) {
@@ -43,54 +38,26 @@ InputMethodKeyboardControllerFuchsia::~InputMethodKeyboardControllerFuchsia() =
default;
bool InputMethodKeyboardControllerFuchsia::DisplayVirtualKeyboard() {
- if (!ime_) {
- // TODO(crbug.com/876934): Instantiate the IME with details about the
- // current composition.
- fuchsia::ui::input::TextInputState state = {};
- state.text = "";
- ime_service_->GetInputMethodEditor(
- fuchsia::ui::input::KeyboardType::TEXT,
- fuchsia::ui::input::InputMethodAction::UNSPECIFIED, std::move(state),
- ime_client_binding_.NewBinding(), ime_.NewRequest());
- }
-
- if (!keyboard_visible_) {
- ime_service_->ShowKeyboard();
- }
-
+ ime_service_->ShowKeyboard();
return true;
}
void InputMethodKeyboardControllerFuchsia::DismissVirtualKeyboard() {
- if (keyboard_visible_) {
- ime_service_->HideKeyboard();
- }
+ ime_service_->HideKeyboard();
}
void InputMethodKeyboardControllerFuchsia::AddObserver(
- InputMethodKeyboardControllerObserver* observer) {}
+ InputMethodKeyboardControllerObserver* observer) {
+ NOTIMPLEMENTED();
+}
void InputMethodKeyboardControllerFuchsia::RemoveObserver(
- InputMethodKeyboardControllerObserver* observer) {}
+ InputMethodKeyboardControllerObserver* observer) {
+ NOTIMPLEMENTED();
+}
bool InputMethodKeyboardControllerFuchsia::IsKeyboardVisible() {
return keyboard_visible_;
}
-void InputMethodKeyboardControllerFuchsia::DidUpdateState(
- fuchsia::ui::input::TextInputState state,
- std::unique_ptr<fuchsia::ui::input::InputEvent> input_event) {
- if (input_event->is_keyboard())
- event_converter_.ProcessEvent(*input_event);
-}
-
-void InputMethodKeyboardControllerFuchsia::OnAction(
- fuchsia::ui::input::InputMethodAction action) {
- // Synthesize an ENTER keypress and send it to the Window.
- KeyEvent key_event(ET_KEY_PRESSED, KeyboardCode::VKEY_RETURN,
- ui::DomCode::ENTER, ui::EF_NONE, ui::DomKey::ENTER,
- ui::EventTimeForNow());
- input_method_->DispatchKeyEvent(&key_event);
-}
-
} // namespace ui
diff --git a/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h b/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h
index 01b53ea2704..e3d074d1f78 100644
--- a/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h
+++ b/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h
@@ -6,25 +6,21 @@
#define UI_BASE_IME_FUCHSIA_INPUT_METHOD_KEYBOARD_CONTROLLER_FUCHSIA_H_
#include <fuchsia/ui/input/cpp/fidl.h>
-#include <lib/fidl/cpp/binding.h>
-#include <memory>
#include "base/macros.h"
-#include "ui/base/ime/input_method_fuchsia.h"
#include "ui/base/ime/input_method_keyboard_controller.h"
#include "ui/base/ime/ui_base_ime_export.h"
-#include "ui/events/fuchsia/input_event_dispatcher.h"
namespace ui {
-// Handles input events from the Fuchsia on-screen keyboard.
+// Manages visibility of the onscreen keyboard.
class UI_BASE_IME_EXPORT InputMethodKeyboardControllerFuchsia
- : public InputMethodKeyboardController,
- public fuchsia::ui::input::InputMethodEditorClient {
+ : public InputMethodKeyboardController {
public:
- // |input_method|: Pointer to the parent InputMethod which owns |this|.
+ // |ime_service| must outlive |this|.
explicit InputMethodKeyboardControllerFuchsia(
- InputMethodFuchsia* input_method);
+ fuchsia::ui::input::ImeService* ime_service);
+
~InputMethodKeyboardControllerFuchsia() override;
// InputMethodKeyboardController implementation.
@@ -35,21 +31,9 @@ class UI_BASE_IME_EXPORT InputMethodKeyboardControllerFuchsia
bool IsKeyboardVisible() override;
private:
- // InputMethodEditorClient implementation.
- void DidUpdateState(
- fuchsia::ui::input::TextInputState state,
- std::unique_ptr<fuchsia::ui::input::InputEvent> input_event) override;
- void OnAction(fuchsia::ui::input::InputMethodAction action) override;
-
- bool keyboard_visible_ = false;
- InputEventDispatcher event_converter_;
- fidl::Binding<fuchsia::ui::input::InputMethodEditorClient>
- ime_client_binding_;
- fuchsia::ui::input::ImeServicePtr ime_service_;
- fuchsia::ui::input::InputMethodEditorPtr ime_;
+ fuchsia::ui::input::ImeService* const ime_service_;
fuchsia::ui::input::ImeVisibilityServicePtr ime_visibility_;
-
- InputMethodFuchsia* input_method_;
+ bool keyboard_visible_ = false;
DISALLOW_COPY_AND_ASSIGN(InputMethodKeyboardControllerFuchsia);
};
diff --git a/chromium/ui/base/ime/ime_bridge.cc b/chromium/ui/base/ime/ime_bridge.cc
index f196d8a7894..5db2a8e415b 100644
--- a/chromium/ui/base/ime/ime_bridge.cc
+++ b/chromium/ui/base/ime/ime_bridge.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
+#include "base/observer_list.h"
#include "build/build_config.h"
namespace ui {
@@ -18,28 +19,12 @@ static IMEBridge* g_ime_bridge = nullptr;
// An implementation of IMEBridge.
class IMEBridgeImpl : public IMEBridge {
public:
-#if defined(OS_CHROMEOS)
- IMEBridgeImpl()
- : input_context_handler_(nullptr),
- engine_handler_(nullptr),
- observer_(nullptr),
- current_input_context_(ui::TEXT_INPUT_TYPE_NONE,
- ui::TEXT_INPUT_MODE_DEFAULT,
- 0,
- ui::TextInputClient::FOCUS_REASON_NONE,
- false /* should_do_learning */),
- candidate_window_handler_(nullptr) {}
-#else
IMEBridgeImpl()
- : input_context_handler_(nullptr),
- engine_handler_(nullptr),
- observer_(nullptr),
- current_input_context_(ui::TEXT_INPUT_TYPE_NONE,
+ : current_input_context_(ui::TEXT_INPUT_TYPE_NONE,
ui::TEXT_INPUT_MODE_DEFAULT,
0,
ui::TextInputClient::FOCUS_REASON_NONE,
false /* should_do_learning */) {}
-#endif
~IMEBridgeImpl() override {}
@@ -52,6 +37,8 @@ class IMEBridgeImpl : public IMEBridge {
void SetInputContextHandler(
IMEInputContextHandlerInterface* handler) override {
input_context_handler_ = handler;
+ for (auto& observer : observers_)
+ observer.OnInputContextHandlerChanged();
}
// IMEBridge override.
@@ -77,14 +64,19 @@ class IMEBridgeImpl : public IMEBridge {
}
// IMEBridge override.
- void SetObserver(ui::IMEBridgeObserver* observer) override {
- observer_ = observer;
+ void AddObserver(ui::IMEBridgeObserver* observer) override {
+ observers_.AddObserver(observer);
+ }
+
+ // IMEBridge override.
+ void RemoveObserver(ui::IMEBridgeObserver* observer) override {
+ observers_.RemoveObserver(observer);
}
// IMEBridge override.
void MaybeSwitchEngine() override {
- if (observer_)
- observer_->OnRequestSwitchEngine();
+ for (auto& observer : observers_)
+ observer.OnRequestSwitchEngine();
}
#if defined(OS_CHROMEOS)
@@ -102,13 +94,14 @@ class IMEBridgeImpl : public IMEBridge {
#endif
private:
- IMEInputContextHandlerInterface* input_context_handler_;
- IMEEngineHandlerInterface* engine_handler_;
- IMEBridgeObserver* observer_;
+ IMEInputContextHandlerInterface* input_context_handler_ = nullptr;
+ IMEEngineHandlerInterface* engine_handler_ = nullptr;
+ base::ObserverList<IMEBridgeObserver> observers_;
IMEEngineHandlerInterface::InputContext current_input_context_;
#if defined(OS_CHROMEOS)
- chromeos::IMECandidateWindowHandlerInterface* candidate_window_handler_;
+ chromeos::IMECandidateWindowHandlerInterface* candidate_window_handler_ =
+ nullptr;
#endif
DISALLOW_COPY_AND_ASSIGN(IMEBridgeImpl);
diff --git a/chromium/ui/base/ime/ime_bridge.h b/chromium/ui/base/ime/ime_bridge.h
index e18c03a27b2..0a807f68703 100644
--- a/chromium/ui/base/ime/ime_bridge.h
+++ b/chromium/ui/base/ime/ime_bridge.h
@@ -64,8 +64,9 @@ class UI_BASE_IME_EXPORT IMEBridge {
virtual const IMEEngineHandlerInterface::InputContext&
GetCurrentInputContext() const = 0;
- // Sets the observer that observes the switching engine event.
- virtual void SetObserver(ui::IMEBridgeObserver* observer) = 0;
+ // Add or remove observers of events such as switching engines, etc.
+ virtual void AddObserver(ui::IMEBridgeObserver* observer) = 0;
+ virtual void RemoveObserver(ui::IMEBridgeObserver* observer) = 0;
// Switches the engine handler upon top level window focus change.
virtual void MaybeSwitchEngine() = 0;
diff --git a/chromium/ui/base/ime/ime_bridge_observer.h b/chromium/ui/base/ime/ime_bridge_observer.h
index a21c5f85a41..74dd8e99187 100644
--- a/chromium/ui/base/ime/ime_bridge_observer.h
+++ b/chromium/ui/base/ime/ime_bridge_observer.h
@@ -5,17 +5,19 @@
#ifndef UI_BASE_IME_IME_BRIDGE_OBSERVER_H_
#define UI_BASE_IME_IME_BRIDGE_OBSERVER_H_
+#include "base/observer_list_types.h"
#include "ui/base/ime/ui_base_ime_export.h"
namespace ui {
-// A interface to .
-class UI_BASE_IME_EXPORT IMEBridgeObserver {
+// A interface to observe changes in the IMEBridge.
+class UI_BASE_IME_EXPORT IMEBridgeObserver : public base::CheckedObserver {
public:
- virtual ~IMEBridgeObserver() {}
-
// Called when requesting to switch the engine handler from ui::InputMethod.
virtual void OnRequestSwitchEngine() = 0;
+
+ // Called when the input context handler has changed, a signal of IME change.
+ virtual void OnInputContextHandlerChanged() = 0;
};
} // namespace ui
diff --git a/chromium/ui/base/ime/ime_engine_handler_interface.h b/chromium/ui/base/ime/ime_engine_handler_interface.h
index fdca0ee898f..f437af5bf6b 100644
--- a/chromium/ui/base/ime/ime_engine_handler_interface.h
+++ b/chromium/ui/base/ime/ime_engine_handler_interface.h
@@ -162,6 +162,10 @@ class UI_BASE_IME_EXPORT IMEEngineHandlerInterface {
// Hides the input view window (from API call).
virtual void HideInputView() = 0;
+ // Sets the mirroring/casting enable states.
+ virtual void SetMirroringEnabled(bool mirroring_enabled) = 0;
+ virtual void SetCastingEnabled(bool casting_enabled) = 0;
+
#elif defined(OS_LINUX) || defined(OS_WIN)
// Get the id of the IME extension.
diff --git a/chromium/ui/base/ime/input_method_auralinux.cc b/chromium/ui/base/ime/input_method_auralinux.cc
index f7343b30c07..9a793126005 100644
--- a/chromium/ui/base/ime/input_method_auralinux.cc
+++ b/chromium/ui/base/ime/input_method_auralinux.cc
@@ -281,7 +281,7 @@ void InputMethodAuraLinux::OnCaretBoundsChanged(const TextInputClient* client) {
base::string16 text;
if (client->GetTextRange(&text_range) &&
client->GetTextFromRange(text_range, &text) &&
- client->GetSelectionRange(&selection_range)) {
+ client->GetEditableSelectionRange(&selection_range)) {
context_->SetSurroundingText(text, selection_range);
}
diff --git a/chromium/ui/base/ime/input_method_auralinux_unittest.cc b/chromium/ui/base/ime/input_method_auralinux_unittest.cc
index 2496391504e..cc67ef7d7e4 100644
--- a/chromium/ui/base/ime/input_method_auralinux_unittest.cc
+++ b/chromium/ui/base/ime/input_method_auralinux_unittest.cc
@@ -252,7 +252,7 @@ class TextInputClientForTesting : public DummyTextInputClient {
*range = text_range;
return true;
}
- bool GetSelectionRange(gfx::Range* range) const override {
+ bool GetEditableSelectionRange(gfx::Range* range) const override {
*range = selection_range;
return true;
}
diff --git a/chromium/ui/base/ime/input_method_base.cc b/chromium/ui/base/ime/input_method_base.cc
index 76f14cac5af..c57c8b57a18 100644
--- a/chromium/ui/base/ime/input_method_base.cc
+++ b/chromium/ui/base/ime/input_method_base.cc
@@ -259,9 +259,13 @@ SurroundingTextInfo InputMethodBase::GetSurroundingTextInfo() {
TextInputClient* client = GetTextInputClient();
if (!client->GetTextRange(&text_range) ||
!client->GetTextFromRange(text_range, &info.surrounding_text) ||
- !client->GetSelectionRange(&info.selection_range)) {
+ !client->GetEditableSelectionRange(&info.selection_range)) {
return SurroundingTextInfo();
}
+ // Makes the |selection_range| be relative to the |surrounding_text|.
+ info.selection_range.set_start(info.selection_range.start() -
+ text_range.start());
+ info.selection_range.set_end(info.selection_range.end() - text_range.start());
return info;
}
diff --git a/chromium/ui/base/ime/input_method_chromeos.cc b/chromium/ui/base/ime/input_method_chromeos.cc
index 918bd6eca9a..cb583c9dbd8 100644
--- a/chromium/ui/base/ime/input_method_chromeos.cc
+++ b/chromium/ui/base/ime/input_method_chromeos.cc
@@ -199,11 +199,13 @@ void InputMethodChromeOS::OnTextInputTypeChanged(
engine->FocusIn(context);
}
+ OnCaretBoundsChanged(client);
+
InputMethodBase::OnTextInputTypeChanged(client);
}
void InputMethodChromeOS::OnCaretBoundsChanged(const TextInputClient* client) {
- if (!IsInputFieldFocused() || !IsTextInputClientFocused(client))
+ if (IsTextInputTypeNone() || !IsTextInputClientFocused(client))
return;
NotifyTextInputCaretBoundsChanged(client);
@@ -240,7 +242,7 @@ void InputMethodChromeOS::OnCaretBoundsChanged(const TextInputClient* client) {
base::string16 surrounding_text;
if (!client->GetTextRange(&text_range) ||
!client->GetTextFromRange(text_range, &surrounding_text) ||
- !client->GetSelectionRange(&selection_range)) {
+ !client->GetEditableSelectionRange(&selection_range)) {
previous_surrounding_text_.clear();
previous_selection_range_ = gfx::Range::InvalidRange();
return;
@@ -315,6 +317,8 @@ void InputMethodChromeOS::OnDidChangeFocusedClient(
GetClientFocusReason(), GetClientShouldDoLearning());
GetEngine()->FocusIn(context);
}
+
+ OnCaretBoundsChanged(GetTextInputClient());
}
void InputMethodChromeOS::ConfirmCompositionText() {
@@ -359,9 +363,6 @@ void InputMethodChromeOS::UpdateContextFocusState() {
GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
GetClientFocusReason(), GetClientShouldDoLearning());
ui::IMEBridge::Get()->SetCurrentInputContext(context);
-
- if (!IsTextInputTypeNone())
- OnCaretBoundsChanged(GetTextInputClient());
}
ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventPostIME(
diff --git a/chromium/ui/base/ime/input_method_chromeos.h b/chromium/ui/base/ime/input_method_chromeos.h
index 893ac1139d2..52942a609a7 100644
--- a/chromium/ui/base/ime/input_method_chromeos.h
+++ b/chromium/ui/base/ime/input_method_chromeos.h
@@ -41,6 +41,12 @@ class UI_BASE_IME_EXPORT InputMethodChromeOS : public InputMethodBase {
bool IsCandidatePopupOpen() const override;
InputMethodKeyboardController* GetInputMethodKeyboardController() override;
+ // Overridden from InputMethodBase:
+ void OnWillChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) override;
+ void OnDidChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) override;
+
protected:
// Converts |text| into CompositionText.
void ExtractCompositionText(const CompositionText& text,
@@ -60,12 +66,6 @@ class UI_BASE_IME_EXPORT InputMethodChromeOS : public InputMethodBase {
private:
class PendingKeyEvent;
- // Overridden from InputMethodBase:
- void OnWillChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) override;
- void OnDidChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) override;
-
// Asks the client to confirm current composition text.
void ConfirmCompositionText();
diff --git a/chromium/ui/base/ime/input_method_chromeos_unittest.cc b/chromium/ui/base/ime/input_method_chromeos_unittest.cc
index 5b4a72a861f..559f34d0ce4 100644
--- a/chromium/ui/base/ime/input_method_chromeos_unittest.cc
+++ b/chromium/ui/base/ime/input_method_chromeos_unittest.cc
@@ -13,6 +13,7 @@
#include "base/i18n/char_iterator.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h"
#include "ui/base/ime/chromeos/mock_ime_engine_handler.h"
@@ -187,6 +188,14 @@ class TestInputMethodManager
DISALLOW_COPY_AND_ASSIGN(TestInputMethodManager);
};
+class NiceMockIMEEngine : public chromeos::MockIMEEngineHandler {
+ public:
+ MOCK_METHOD1(FocusIn, void(const InputContext&));
+ MOCK_METHOD0(FocusOut, void());
+ MOCK_METHOD4(SetSurroundingText,
+ void(const std::string&, uint32_t, uint32_t, uint32_t));
+};
+
class InputMethodChromeOSTest : public internal::InputMethodDelegate,
public testing::Test,
public DummyTextInputClient {
@@ -275,7 +284,7 @@ class InputMethodChromeOSTest : public internal::InputMethodDelegate,
*range = text_range_;
return true;
}
- bool GetSelectionRange(gfx::Range* range) const override {
+ bool GetEditableSelectionRange(gfx::Range* range) const override {
*range = selection_range_;
return true;
}
@@ -826,6 +835,43 @@ TEST_F(InputMethodChromeOSTest, SurroundingText_BecomeEmptyText) {
mock_ime_engine_handler_->set_surrounding_text_call_count());
}
+TEST_F(InputMethodChromeOSTest, SurroundingText_EventOrder) {
+ ::testing::NiceMock<NiceMockIMEEngine> mock_engine;
+ IMEBridge::Get()->SetCurrentEngineHandler(&mock_engine);
+
+ {
+ // Switches the text input client.
+ ::testing::InSequence seq;
+ EXPECT_CALL(mock_engine, FocusOut);
+ EXPECT_CALL(mock_engine, FocusIn);
+ EXPECT_CALL(mock_engine, SetSurroundingText);
+
+ surrounding_text_ = UTF8ToUTF16("a");
+ text_range_ = gfx::Range(0, 1);
+ selection_range_ = gfx::Range(0, 0);
+
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnWillChangeFocusedClient(nullptr, this);
+ ime_->OnDidChangeFocusedClient(nullptr, this);
+ }
+
+ {
+ // Changes text input type.
+ ::testing::InSequence seq;
+ EXPECT_CALL(mock_engine, FocusOut);
+ EXPECT_CALL(mock_engine, FocusIn);
+ EXPECT_CALL(mock_engine, SetSurroundingText);
+
+ surrounding_text_ = UTF8ToUTF16("b");
+ text_range_ = gfx::Range(0, 1);
+ selection_range_ = gfx::Range(0, 0);
+
+ input_type_ = TEXT_INPUT_TYPE_EMAIL;
+ ime_->OnTextInputTypeChanged(this);
+ }
+ IMEBridge::Get()->SetCurrentEngineHandler(nullptr);
+}
+
class InputMethodChromeOSKeyEventTest : public InputMethodChromeOSTest {
public:
InputMethodChromeOSKeyEventTest() {}
diff --git a/chromium/ui/base/ime/input_method_fuchsia.cc b/chromium/ui/base/ime/input_method_fuchsia.cc
index 83f18d4df01..0ce7f336291 100644
--- a/chromium/ui/base/ime/input_method_fuchsia.cc
+++ b/chromium/ui/base/ime/input_method_fuchsia.cc
@@ -10,22 +10,26 @@
#include "base/bind_helpers.h"
#include "base/fuchsia/component_context.h"
-#include "ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
namespace ui {
InputMethodFuchsia::InputMethodFuchsia(internal::InputMethodDelegate* delegate)
- : InputMethodBase(delegate) {
- virtual_keyboard_controller_ =
- std::make_unique<InputMethodKeyboardControllerFuchsia>(this);
-}
+ : InputMethodBase(delegate),
+ event_converter_(this),
+ ime_client_binding_(this),
+ ime_service_(base::fuchsia::ComponentContext::GetDefault()
+ ->ConnectToService<fuchsia::ui::input::ImeService>()),
+ virtual_keyboard_controller_(ime_service_.get()) {}
InputMethodFuchsia::~InputMethodFuchsia() {}
InputMethodKeyboardController*
InputMethodFuchsia::GetInputMethodKeyboardController() {
- return virtual_keyboard_controller_.get();
+ return &virtual_keyboard_controller_;
}
void InputMethodFuchsia::DispatchEvent(ui::Event* event) {
@@ -63,4 +67,46 @@ bool InputMethodFuchsia::IsCandidatePopupOpen() const {
return false;
}
+void InputMethodFuchsia::OnFocus() {
+ DCHECK(!ime_);
+
+ // TODO(crbug.com/876934): Instantiate the IME with details about the text
+ // being edited.
+ fuchsia::ui::input::TextInputState state = {};
+ state.text = "";
+ ime_service_->GetInputMethodEditor(
+ fuchsia::ui::input::KeyboardType::TEXT,
+ fuchsia::ui::input::InputMethodAction::UNSPECIFIED, std::move(state),
+ ime_client_binding_.NewBinding(), ime_.NewRequest());
+}
+
+void InputMethodFuchsia::OnBlur() {
+ virtual_keyboard_controller_.DismissVirtualKeyboard();
+ ime_client_binding_.Unbind();
+ ime_.Unbind();
+}
+
+void InputMethodFuchsia::DidUpdateState(
+ fuchsia::ui::input::TextInputState state,
+ std::unique_ptr<fuchsia::ui::input::InputEvent> input_event) {
+ if (input_event->is_keyboard())
+ event_converter_.ProcessEvent(*input_event);
+ else
+ NOTIMPLEMENTED();
+}
+
+void InputMethodFuchsia::OnAction(
+ fuchsia::ui::input::InputMethodAction action) {
+ if (action != fuchsia::ui::input::InputMethodAction::UNSPECIFIED) {
+ NOTIMPLEMENTED();
+ return;
+ }
+
+ // Synthesize an ENTER keypress and send it to the Window.
+ KeyEvent key_event(ET_KEY_PRESSED, KeyboardCode::VKEY_RETURN,
+ ui::DomCode::ENTER, ui::EF_NONE, ui::DomKey::ENTER,
+ ui::EventTimeForNow());
+ DispatchKeyEvent(&key_event);
+}
+
} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_fuchsia.h b/chromium/ui/base/ime/input_method_fuchsia.h
index 0c72098c283..3137db598c5 100644
--- a/chromium/ui/base/ime/input_method_fuchsia.h
+++ b/chromium/ui/base/ime/input_method_fuchsia.h
@@ -6,40 +6,67 @@
#define UI_BASE_IME_INPUT_METHOD_FUCHSIA_H_
#include <fuchsia/ui/input/cpp/fidl.h>
+#include <lib/fidl/cpp/binding.h>
#include <memory>
#include "base/macros.h"
+#include "ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h"
#include "ui/base/ime/input_method_base.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/base/ime/ui_base_ime_export.h"
+#include "ui/events/fuchsia/input_event_dispatcher.h"
#include "ui/events/fuchsia/input_event_dispatcher_delegate.h"
#include "ui/gfx/native_widget_types.h"
namespace ui {
-class InputMethodKeyboardControllerFuchsia;
-
-// Hnadles input from physical keyboards and the IME service.
+// Handles input from physical keyboards and the IME service.
class UI_BASE_IME_EXPORT InputMethodFuchsia
: public InputMethodBase,
- public InputEventDispatcherDelegate {
+ public InputEventDispatcherDelegate,
+ public fuchsia::ui::input::InputMethodEditorClient {
public:
explicit InputMethodFuchsia(internal::InputMethodDelegate* delegate);
~InputMethodFuchsia() override;
+ fuchsia::ui::input::ImeService* ime_service() const {
+ return ime_service_.get();
+ }
+
// InputMethodBase interface implementation.
InputMethodKeyboardController* GetInputMethodKeyboardController() override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
void OnCaretBoundsChanged(const TextInputClient* client) override;
void CancelComposition(const TextInputClient* client) override;
bool IsCandidatePopupOpen() const override;
+ void OnFocus() override;
+ void OnBlur() override;
private:
+ // Establishes a connection to the input service and starts receiving input
+ // events from hard and soft keyboards.
+ void ConnectInputService();
+
+ // Terminates the connection to the input services, which stops receiving
+ // input events.
+ void DisconnectInputService();
+
// InputEventDispatcherDelegate interface implementation.
void DispatchEvent(ui::Event* event) override;
- std::unique_ptr<InputMethodKeyboardControllerFuchsia>
- virtual_keyboard_controller_;
+ // InputMethodEditorClient interface implementation.
+ void DidUpdateState(
+ fuchsia::ui::input::TextInputState state,
+ std::unique_ptr<fuchsia::ui::input::InputEvent> input_event) override;
+ void OnAction(fuchsia::ui::input::InputMethodAction action) override;
+
+ InputEventDispatcher event_converter_;
+ fidl::Binding<fuchsia::ui::input::InputMethodEditorClient>
+ ime_client_binding_;
+ fuchsia::ui::input::ImeServicePtr ime_service_;
+ fuchsia::ui::input::InputMethodEditorPtr ime_;
+ fuchsia::ui::input::ImeVisibilityServicePtr ime_visibility_;
+ InputMethodKeyboardControllerFuchsia virtual_keyboard_controller_;
DISALLOW_COPY_AND_ASSIGN(InputMethodFuchsia);
};
diff --git a/chromium/ui/base/ime/input_method_win_base.cc b/chromium/ui/base/ime/input_method_win_base.cc
index 333607e76ea..6b7c3bef62a 100644
--- a/chromium/ui/base/ime/input_method_win_base.cc
+++ b/chromium/ui/base/ime/input_method_win_base.cc
@@ -350,7 +350,8 @@ LRESULT InputMethodWinBase::OnDocumentFeed(RECONVERTSTRING* reconv) {
result = client->GetCompositionTextRange(&target_range);
if (!result || target_range.is_empty()) {
- if (!client->GetSelectionRange(&target_range) || !target_range.IsValid()) {
+ if (!client->GetEditableSelectionRange(&target_range) ||
+ !target_range.IsValid()) {
return 0;
}
}
@@ -411,7 +412,7 @@ LRESULT InputMethodWinBase::OnReconvertString(RECONVERTSTRING* reconv) {
return 0;
gfx::Range selection_range;
- if (!client->GetSelectionRange(&selection_range) ||
+ if (!client->GetEditableSelectionRange(&selection_range) ||
selection_range.is_empty()) {
return 0;
}
diff --git a/chromium/ui/base/ime/linux/fake_input_method_context_factory.cc b/chromium/ui/base/ime/linux/fake_input_method_context_factory.cc
index f8d3102ee48..aba2f76ed30 100644
--- a/chromium/ui/base/ime/linux/fake_input_method_context_factory.cc
+++ b/chromium/ui/base/ime/linux/fake_input_method_context_factory.cc
@@ -8,7 +8,9 @@
namespace ui {
-FakeInputMethodContextFactory::FakeInputMethodContextFactory() {}
+FakeInputMethodContextFactory::FakeInputMethodContextFactory() = default;
+
+FakeInputMethodContextFactory::~FakeInputMethodContextFactory() = default;
std::unique_ptr<LinuxInputMethodContext>
FakeInputMethodContextFactory::CreateInputMethodContext(
diff --git a/chromium/ui/base/ime/linux/fake_input_method_context_factory.h b/chromium/ui/base/ime/linux/fake_input_method_context_factory.h
index 12bb7661b1e..1d5f8b86a78 100644
--- a/chromium/ui/base/ime/linux/fake_input_method_context_factory.h
+++ b/chromium/ui/base/ime/linux/fake_input_method_context_factory.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
+#include "ui/base/ime/linux/ui_base_ime_linux_export.h"
namespace ui {
@@ -16,6 +17,7 @@ class UI_BASE_IME_LINUX_EXPORT FakeInputMethodContextFactory
: public LinuxInputMethodContextFactory {
public:
FakeInputMethodContextFactory();
+ ~FakeInputMethodContextFactory() override;
// LinuxInputMethodContextFactory:
std::unique_ptr<LinuxInputMethodContext> CreateInputMethodContext(
diff --git a/chromium/ui/base/ime/text_input_client.h b/chromium/ui/base/ime/text_input_client.h
index c475c432dcf..7209084139a 100644
--- a/chromium/ui/base/ime/text_input_client.h
+++ b/chromium/ui/base/ime/text_input_client.h
@@ -118,35 +118,37 @@ class UI_BASE_IME_EXPORT TextInputClient {
// Document content operations ----------------------------------------------
- // Retrieves the UTF-16 based character range containing accessible text in
+ // Retrieves the UTF-16 code unit range containing accessible text in
// the View. It must cover the composition and selection range.
// Returns false if the information cannot be retrieved right now.
virtual bool GetTextRange(gfx::Range* range) const = 0;
- // Retrieves the UTF-16 based character range of current composition text.
+ // Retrieves the UTF-16 code unit range of current composition text.
// Returns false if the information cannot be retrieved right now.
virtual bool GetCompositionTextRange(gfx::Range* range) const = 0;
- // Retrieves the UTF-16 based character range of current selection.
- // Returns false if the information cannot be retrieved right now.
- virtual bool GetSelectionRange(gfx::Range* range) const = 0;
+ // Retrieves the UTF-16 code unit range of current selection in the text
+ // input. Returns false if the information cannot be retrieved right now.
+ // Returns false if the selected text is outside of the text input (== the
+ // text input is not focused)
+ virtual bool GetEditableSelectionRange(gfx::Range* range) const = 0;
- // Selects the given UTF-16 based character range. Current composition text
+ // Selects the given UTF-16 code unit range. Current composition text
// will be confirmed before selecting the range.
// Returns false if the operation is not supported.
- virtual bool SetSelectionRange(const gfx::Range& range) = 0;
+ virtual bool SetEditableSelectionRange(const gfx::Range& range) = 0;
- // Deletes contents in the given UTF-16 based character range. Current
+ // Deletes contents in the given UTF-16 code unit range. Current
// composition text will be confirmed before deleting the range.
// The input caret will be moved to the place where the range gets deleted.
// ExtendSelectionAndDelete should be used instead as far as you are deleting
// characters around current caret. This function with the range based on
- // GetSelectionRange has a race condition due to asynchronous IPCs between
- // browser and renderer.
- // Returns false if the operation is not supported.
+ // GetEditableSelectionRange has a race condition due to asynchronous IPCs
+ // between browser and renderer. Returns false if the operation is not
+ // supported.
virtual bool DeleteRange(const gfx::Range& range) = 0;
- // Retrieves the text content in a given UTF-16 based character range.
+ // Retrieves the text content in a given UTF-16 code unit range.
// The result will be stored into |*text|.
// Returns false if the operation is not supported or the specified range
// is out of the text range returned by GetTextRange().
@@ -166,11 +168,11 @@ class UI_BASE_IME_EXPORT TextInputClient {
virtual bool ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) = 0;
- // Deletes the current selection plus the specified number of characters
+ // Deletes the current selection plus the specified number of char16 values
// before and after the selection or caret. This function should be used
- // instead of calling DeleteRange with GetSelectionRange, because
- // GetSelectionRange may not be the latest value due to asynchronous of IPC
- // between browser and renderer.
+ // instead of calling DeleteRange with GetEditableSelectionRange, because
+ // GetEditableSelectionRange may not be the latest value due to asynchronous
+ // of IPC between browser and renderer.
virtual void ExtendSelectionAndDelete(size_t before, size_t after) = 0;
// Ensure the caret is not in |rect|. |rect| is in screen coordinates in
diff --git a/chromium/ui/base/ime/win/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc
index eab3ad63a3e..f3f094c5432 100644
--- a/chromium/ui/base/ime/win/tsf_bridge.cc
+++ b/chromium/ui/base/ime/win/tsf_bridge.cc
@@ -10,6 +10,7 @@
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/no_destructor.h"
+#include "base/stl_util.h"
#include "base/threading/thread_local_storage.h"
#include "base/win/scoped_variant.h"
#include "ui/base/ime/text_input_client.h"
@@ -354,7 +355,7 @@ bool TSFBridgeImpl::InitializeDocumentMapInternal() {
TEXT_INPUT_TYPE_EMAIL, TEXT_INPUT_TYPE_NUMBER,
TEXT_INPUT_TYPE_TELEPHONE, TEXT_INPUT_TYPE_URL,
};
- for (size_t i = 0; i < arraysize(kTextInputTypes); ++i) {
+ for (size_t i = 0; i < base::size(kTextInputTypes); ++i) {
const TextInputType input_type = kTextInputTypes[i];
Microsoft::WRL::ComPtr<ITfContext> context;
Microsoft::WRL::ComPtr<ITfDocumentMgr> document_manager;
diff --git a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
index a65641e1a55..42380434e08 100644
--- a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -10,8 +10,8 @@
#include <OleCtl.h>
#include <wrl/client.h>
-#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_variant.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -47,8 +47,8 @@ class MockTextInputClient : public TextInputClient {
MOCK_METHOD0(ShouldDoLearning, bool());
MOCK_CONST_METHOD1(GetTextRange, bool(gfx::Range*));
MOCK_CONST_METHOD1(GetCompositionTextRange, bool(gfx::Range*));
- MOCK_CONST_METHOD1(GetSelectionRange, bool(gfx::Range*));
- MOCK_METHOD1(SetSelectionRange, bool(const gfx::Range&));
+ MOCK_CONST_METHOD1(GetEditableSelectionRange, bool(gfx::Range*));
+ MOCK_METHOD1(SetEditableSelectionRange, bool(const gfx::Range&));
MOCK_METHOD1(DeleteRange, bool(const gfx::Range&));
MOCK_CONST_METHOD2(GetTextFromRange,
bool(const gfx::Range&, base::string16*));
@@ -1239,11 +1239,11 @@ TEST_F(TSFTextStoreTest, RequestSupportedAttrs) {
const TS_ATTRID kUnknownAttributes[] = {GUID_NULL};
EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(
- 0, arraysize(kUnknownAttributes), kUnknownAttributes))
+ 0, base::size(kUnknownAttributes), kUnknownAttributes))
<< "Must fail for unknown attributes";
const TS_ATTRID kAttributes[] = {GUID_NULL, GUID_PROP_INPUTSCOPE, GUID_NULL};
- EXPECT_EQ(S_OK, text_store_->RequestSupportedAttrs(0, arraysize(kAttributes),
+ EXPECT_EQ(S_OK, text_store_->RequestSupportedAttrs(0, base::size(kAttributes),
kAttributes))
<< "InputScope must be supported";
@@ -1253,7 +1253,7 @@ TEST_F(TSFTextStoreTest, RequestSupportedAttrs) {
text_store_->SetFocusedTextInputClient(nullptr, nullptr);
EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 0, nullptr));
EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(
- 0, arraysize(kAttributes), kAttributes));
+ 0, base::size(kAttributes), kAttributes));
}
}
@@ -1271,7 +1271,7 @@ TEST_F(TSFTextStoreTest, RetrieveRequestedAttrs) {
SCOPED_TRACE("Make sure if InputScope is supported");
TS_ATTRVAL buffer[2] = {};
num_copied = 0xfffffff;
- ASSERT_EQ(S_OK, text_store_->RetrieveRequestedAttrs(arraysize(buffer),
+ ASSERT_EQ(S_OK, text_store_->RetrieveRequestedAttrs(base::size(buffer),
buffer, &num_copied));
bool input_scope_found = false;
for (size_t i = 0; i < num_copied; ++i) {
@@ -1296,7 +1296,7 @@ TEST_F(TSFTextStoreTest, RetrieveRequestedAttrs) {
num_copied = 0xfffffff;
TS_ATTRVAL buffer[2] = {};
EXPECT_HRESULT_FAILED(text_store_->RetrieveRequestedAttrs(
- arraysize(buffer), buffer, &num_copied));
+ base::size(buffer), buffer, &num_copied));
}
}
diff --git a/chromium/ui/base/l10n/l10n_util.cc b/chromium/ui/base/l10n/l10n_util.cc
index 1eef9c217fb..3672fe4e878 100644
--- a/chromium/ui/base/l10n/l10n_util.cc
+++ b/chromium/ui/base/l10n/l10n_util.cc
@@ -19,7 +19,7 @@
#include "base/i18n/rtl.h"
#include "base/i18n/string_compare.h"
#include "base/lazy_instance.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -918,7 +918,7 @@ const char* const* GetAcceptLanguageListForTesting() {
}
size_t GetAcceptLanguageListSizeForTesting() {
- return arraysize(kAcceptLanguageList);
+ return base::size(kAcceptLanguageList);
}
} // namespace l10n_util
diff --git a/chromium/ui/base/l10n/l10n_util_android.cc b/chromium/ui/base/l10n/l10n_util_android.cc
index cd3e0e06f35..9b43a7b26a6 100644
--- a/chromium/ui/base/l10n/l10n_util_android.cc
+++ b/chromium/ui/base/l10n/l10n_util_android.cc
@@ -24,7 +24,6 @@ namespace l10n_util {
jint JNI_LocalizationUtils_GetFirstStrongCharacterDirection(
JNIEnv* env,
- const JavaParamRef<jclass>& clazz,
const JavaParamRef<jstring>& string) {
return base::i18n::GetFirstStrongCharacterDirection(
base::android::ConvertJavaStringToUTF16(env, string));
@@ -99,7 +98,6 @@ base::string16 GetDisplayNameForLocale(const std::string& locale,
ScopedJavaLocalRef<jstring> JNI_LocalizationUtils_GetDurationString(
JNIEnv* env,
- const JavaParamRef<jclass>& clazz,
jlong timeInMillis) {
ScopedJavaLocalRef<jstring> jtime_remaining =
base::android::ConvertUTF16ToJavaString(
diff --git a/chromium/ui/base/l10n/l10n_util_mac_unittest.mm b/chromium/ui/base/l10n/l10n_util_mac_unittest.mm
index c760425a8fb..4ae224c0365 100644
--- a/chromium/ui/base/l10n/l10n_util_mac_unittest.mm
+++ b/chromium/ui/base/l10n/l10n_util_mac_unittest.mm
@@ -5,7 +5,7 @@
#import <Foundation/Foundation.h>
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/sys_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -38,7 +38,7 @@ TEST_F(L10nUtilMacTest, FixUpWindowsStyleLabel) {
{ @"foo(&b)...", @"foo\u2026" },
{ @"(&b)foo", @"foo" },
};
- for (size_t idx = 0; idx < arraysize(data); ++idx) {
+ for (size_t idx = 0; idx < base::size(data); ++idx) {
base::string16 input16(base::SysNSStringToUTF16(data[idx].input));
NSString* result = l10n_util::FixUpWindowsStyleLabel(input16);
diff --git a/chromium/ui/base/l10n/l10n_util_posix.cc b/chromium/ui/base/l10n/l10n_util_posix.cc
index b57e78da62f..3f75f324cf2 100644
--- a/chromium/ui/base/l10n/l10n_util_posix.cc
+++ b/chromium/ui/base/l10n/l10n_util_posix.cc
@@ -6,7 +6,7 @@
#include <string>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#if defined(OS_CHROMEOS)
@@ -21,7 +21,7 @@ bool IsLocaleSupportedByOS(const std::string& locale) {
// TODO(jungshik): Once the above issues are resolved, change this back
// to return true.
static const char kUnsupportedLocales[][3] = {"am", "sw"};
- for (size_t i = 0; i < arraysize(kUnsupportedLocales); ++i) {
+ for (size_t i = 0; i < base::size(kUnsupportedLocales); ++i) {
if (base::LowerCaseEqualsASCII(locale, kUnsupportedLocales[i]))
return false;
}
diff --git a/chromium/ui/base/l10n/l10n_util_unittest.cc b/chromium/ui/base/l10n/l10n_util_unittest.cc
index 607d9872f90..ba9a3ea7aeb 100644
--- a/chromium/ui/base/l10n/l10n_util_unittest.cc
+++ b/chromium/ui/base/l10n/l10n_util_unittest.cc
@@ -11,8 +11,8 @@
#include "base/i18n/case_conversion.h"
#include "base/i18n/rtl.h"
#include "base/i18n/time_formatting.h"
-#include "base/macros.h"
#include "base/path_service.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/icu_test_util.h"
@@ -21,6 +21,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "third_party/icu/source/common/unicode/locid.h"
+#include "ui/base/grit/ui_base_test_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_collator.h"
#include "ui/base/ui_base_paths.h"
@@ -29,10 +30,6 @@
#include <cstdlib>
#endif
-#if !defined(OS_MACOSX)
-#include "ui/base/test/data/resource.h"
-#endif
-
using base::ASCIIToUTF16;
using base::UTF8ToUTF16;
@@ -54,9 +51,7 @@ class StringWrapper {
class L10nUtilTest : public PlatformTest {
};
-#if defined(OS_WIN)
-// TODO(beng): disabled until app strings move to app.
-TEST_F(L10nUtilTest, DISABLED_GetString) {
+TEST_F(L10nUtilTest, GetString) {
std::string s = l10n_util::GetStringUTF8(IDS_SIMPLE);
EXPECT_EQ(std::string("Hello World!"), s);
@@ -66,9 +61,11 @@ TEST_F(L10nUtilTest, DISABLED_GetString) {
EXPECT_EQ(std::string("Hello, chrome. Your number is 10."), s);
base::string16 s16 = l10n_util::GetStringFUTF16Int(IDS_PLACEHOLDERS_2, 20);
- EXPECT_EQ(UTF8ToUTF16("You owe me $20."), s16);
+
+ // Consecutive '$' characters override any placeholder functionality.
+ // See //base/strings/string_util.h ReplaceStringPlaceholders().
+ EXPECT_EQ(UTF8ToUTF16("You owe me $$1."), s16);
}
-#endif // defined(OS_WIN)
#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
// On Mac, we are disabling this test because GetApplicationLocale() as an
@@ -114,7 +111,7 @@ TEST_F(L10nUtilTest, GetAppLocale) {
"fr", "he", "nb", "pt-BR", "pt-PT", "zh-CN", "zh-TW",
};
- for (size_t i = 0; i < arraysize(filenames); ++i) {
+ for (size_t i = 0; i < base::size(filenames); ++i) {
base::FilePath filename = new_locale_dir.AppendASCII(
filenames[i] + ".pak");
base::WriteFile(filename, "", 0);
diff --git a/chromium/ui/base/material_design/material_design_controller.cc b/chromium/ui/base/material_design/material_design_controller.cc
index e9700d2188e..bf0caa69189 100644
--- a/chromium/ui/base/material_design/material_design_controller.cc
+++ b/chromium/ui/base/material_design/material_design_controller.cc
@@ -15,13 +15,11 @@
#include "base/observer_list.h"
#include "base/strings/string_number_conversions.h"
#include "build/buildflag.h"
+#include "ui/base/buildflags.h"
#include "ui/base/material_design/material_design_controller_observer.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
-#include "ui/base/ui_features.h"
#include "ui/gfx/animation/linear_animation.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/color_utils.h"
#if defined(OS_WIN)
#include "base/win/win_util.h"
@@ -87,11 +85,8 @@ void MaterialDesignController::Initialize() {
}
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.
- // TODO(crbug.com/864544)
- color_utils::SetDarkestColor(gfx::kGoogleGrey900);
-
+ // TODO(crbug.com/864544): Ideally, there would be a more general, "initialize
+ // random stuff here" function into which this sort of thing can be placed.
double animation_duration_scale;
if (base::StringToDouble(
command_line->GetSwitchValueASCII(switches::kAnimationDurationScale),
diff --git a/chromium/ui/base/models/dialog_model.cc b/chromium/ui/base/models/dialog_model.cc
deleted file mode 100644
index 310bff04c50..00000000000
--- a/chromium/ui/base/models/dialog_model.cc
+++ /dev/null
@@ -1,12 +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.
-
-#include "ui/base/models/dialog_model.h"
-
-namespace ui {
-
-DialogModel::~DialogModel() {
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/models/dialog_model.h b/chromium/ui/base/models/dialog_model.h
deleted file mode 100644
index d42d520cca4..00000000000
--- a/chromium/ui/base/models/dialog_model.h
+++ /dev/null
@@ -1,42 +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_BASE_MODELS_DIALOG_MODEL_H_
-#define UI_BASE_MODELS_DIALOG_MODEL_H_
-
-#include "base/strings/string16.h"
-#include "ui/base/ui_base_export.h"
-#include "ui/base/ui_base_types.h"
-
-namespace ui {
-
-// A model representing a dialog window. The model provides the content to show
-// to the user (i.e. title), and the ways the user can interact with it
-// (i.e. the buttons).
-class UI_BASE_EXPORT DialogModel {
- public:
- virtual ~DialogModel();
-
- // Returns a mask specifying which of the available DialogButtons are visible
- // for the dialog. Note: Dialogs with just an OK button are frowned upon.
- virtual int GetDialogButtons() const = 0;
-
- // Returns the default dialog button. This should not be a mask as only
- // one button should ever be the default button. Return
- // ui::DIALOG_BUTTON_NONE if there is no default. Default
- // behavior is to return ui::DIALOG_BUTTON_OK or
- // ui::DIALOG_BUTTON_CANCEL (in that order) if they are
- // present, ui::DIALOG_BUTTON_NONE otherwise.
- virtual int GetDefaultDialogButton() const = 0;
-
- // Returns the label of the specified dialog button.
- virtual base::string16 GetDialogButtonLabel(DialogButton button) const = 0;
-
- // Returns whether the specified dialog button is enabled.
- virtual bool IsDialogButtonEnabled(DialogButton button) const = 0;
-};
-
-} // namespace ui
-
-#endif // UI_BASE_MODELS_DIALOG_MODEL_H_
diff --git a/chromium/ui/base/models/menu_model.h b/chromium/ui/base/models/menu_model.h
index fb958b187f0..bb53c043a8f 100644
--- a/chromium/ui/base/models/menu_model.h
+++ b/chromium/ui/base/models/menu_model.h
@@ -112,10 +112,6 @@ class UI_BASE_EXPORT MenuModel {
// Returns the model for the submenu at the specified index.
virtual MenuModel* GetSubmenuModelAt(int index) const = 0;
- // Called when the highlighted menu item changes to the item at the specified
- // index.
- virtual void HighlightChangedTo(int index) = 0;
-
// Called when the item at the specified index has been activated.
virtual void ActivatedAt(int index) = 0;
diff --git a/chromium/ui/base/models/simple_menu_model.cc b/chromium/ui/base/models/simple_menu_model.cc
index 4aa19f6ea28..b9fbad7cb81 100644
--- a/chromium/ui/base/models/simple_menu_model.cc
+++ b/chromium/ui/base/models/simple_menu_model.cc
@@ -50,9 +50,6 @@ bool SimpleMenuModel::Delegate::GetIconForCommandId(
return false;
}
-void SimpleMenuModel::Delegate::CommandIdHighlighted(int command_id) {
-}
-
void SimpleMenuModel::Delegate::OnMenuWillShow(SimpleMenuModel* /*source*/) {}
void SimpleMenuModel::Delegate::MenuClosed(SimpleMenuModel* /*source*/) {
@@ -422,11 +419,6 @@ bool SimpleMenuModel::IsVisibleAt(int index) const {
items_[ValidateItemIndex(index)].visible;
}
-void SimpleMenuModel::HighlightChangedTo(int index) {
- if (delegate_)
- delegate_->CommandIdHighlighted(GetCommandIdAt(index));
-}
-
void SimpleMenuModel::ActivatedAt(int index) {
ActivatedAt(index, 0);
}
diff --git a/chromium/ui/base/models/simple_menu_model.h b/chromium/ui/base/models/simple_menu_model.h
index ac1e1a78111..b9f7b9b363f 100644
--- a/chromium/ui/base/models/simple_menu_model.h
+++ b/chromium/ui/base/models/simple_menu_model.h
@@ -46,10 +46,6 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel {
virtual bool GetIconForCommandId(int command_id,
gfx::Image* icon) const;
- // Notifies the delegate that the item with the specified command id was
- // visually highlighted within the menu.
- virtual void CommandIdHighlighted(int command_id);
-
// Performs the action associates with the specified command id.
// The passed |event_flags| are the flags from the event which issued this
// command and they can be examined to find modifier keys.
@@ -185,7 +181,6 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel {
ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override;
bool IsEnabledAt(int index) const override;
bool IsVisibleAt(int index) const override;
- void HighlightChangedTo(int index) override;
void ActivatedAt(int index) override;
void ActivatedAt(int index, int event_flags) override;
MenuModel* GetSubmenuModelAt(int index) const override;
diff --git a/chromium/ui/base/mojo/BUILD.gn b/chromium/ui/base/mojo/BUILD.gn
index bdedff6d980..51bd3fbe676 100644
--- a/chromium/ui/base/mojo/BUILD.gn
+++ b/chromium/ui/base/mojo/BUILD.gn
@@ -7,6 +7,7 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojo") {
sources = [
"clipboard.mojom",
+ "cursor.mojom",
"ui_base_types.mojom",
"window_open_disposition.mojom",
]
@@ -14,6 +15,7 @@ mojom("mojo") {
public_deps = [
"//mojo/public/mojom/base",
"//skia/public/interfaces",
+ "//ui/gfx/geometry/mojo",
"//url/mojom:url_mojom_gurl",
]
}
@@ -32,5 +34,21 @@ source_set("lib") {
"//base",
"//mojo/public/cpp/bindings",
"//ui/base",
+ "//ui/base/clipboard",
+ ]
+}
+
+source_set("unittests") {
+ testonly = true
+ sources = [
+ "cursor_struct_traits_unittest.cc",
+ ]
+ deps = [
+ ":mojo",
+ "//skia/public/interfaces",
+ "//testing/gtest",
+ "//ui/base",
+ "//ui/events",
+ "//ui/gfx/geometry/mojo:struct_traits",
]
}
diff --git a/chromium/ui/base/mojo/DEPS b/chromium/ui/base/mojo/DEPS
index 0e01cbe71d1..3bce672266d 100644
--- a/chromium/ui/base/mojo/DEPS
+++ b/chromium/ui/base/mojo/DEPS
@@ -1,4 +1,6 @@
include_rules = [
+ "+mojo/public/cpp/base",
"+mojo/public/cpp/bindings",
- "+third_party/blink/public/mojom/clipboard/clipboard.mojom-shared.h"
+ "+third_party/blink/public/mojom/clipboard/clipboard.mojom-shared.h",
+ "+skia/public/interfaces"
]
diff --git a/chromium/ui/base/mojo/clipboard_client.cc b/chromium/ui/base/mojo/clipboard_client.cc
index 0424a79d09a..258ff49641e 100644
--- a/chromium/ui/base/mojo/clipboard_client.cc
+++ b/chromium/ui/base/mojo/clipboard_client.cc
@@ -30,7 +30,7 @@ uint64_t ClipboardClient::GetSequenceNumber(ClipboardType type) const {
return sequence_number;
}
-bool ClipboardClient::IsFormatAvailable(const FormatType& format,
+bool ClipboardClient::IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const {
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
bool result = false;
@@ -96,7 +96,7 @@ void ClipboardClient::ReadBookmark(base::string16* title,
clipboard_->ReadBookmark(title, url);
}
-void ClipboardClient::ReadData(const FormatType& format,
+void ClipboardClient::ReadData(const ClipboardFormatType& format,
std::string* result) const {
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
clipboard_->ReadData(format.Serialize(), result);
@@ -157,7 +157,7 @@ void ClipboardClient::WriteBitmap(const SkBitmap& bitmap) {
clipboard_->WriteBitmap(out_bitmap);
}
-void ClipboardClient::WriteData(const FormatType& format,
+void ClipboardClient::WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) {
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
diff --git a/chromium/ui/base/mojo/clipboard_client.h b/chromium/ui/base/mojo/clipboard_client.h
index ac093c3569c..809804e7c20 100644
--- a/chromium/ui/base/mojo/clipboard_client.h
+++ b/chromium/ui/base/mojo/clipboard_client.h
@@ -22,7 +22,7 @@ class ClipboardClient : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
uint64_t GetSequenceNumber(ClipboardType type) const override;
- bool IsFormatAvailable(const FormatType& format,
+ bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardType type) const override;
void Clear(ClipboardType type) override;
void ReadAvailableTypes(ClipboardType type,
@@ -41,7 +41,8 @@ class ClipboardClient : public Clipboard {
const base::string16& type,
base::string16* result) const override;
void ReadBookmark(base::string16* title, std::string* url) const override;
- void ReadData(const FormatType& format, std::string* result) const override;
+ void ReadData(const ClipboardFormatType& format,
+ std::string* result) const override;
void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
void WriteText(const char* text_data, size_t text_len) override;
void WriteHTML(const char* markup_data,
@@ -55,7 +56,7 @@ class ClipboardClient : public Clipboard {
size_t url_len) override;
void WriteWebSmartPaste() override;
void WriteBitmap(const SkBitmap& bitmap) override;
- void WriteData(const FormatType& format,
+ void WriteData(const ClipboardFormatType& format,
const char* data_data,
size_t data_len) override;
diff --git a/chromium/ui/base/mojo/clipboard_host.cc b/chromium/ui/base/mojo/clipboard_host.cc
index 410ea26c966..769dde85fb9 100644
--- a/chromium/ui/base/mojo/clipboard_host.cc
+++ b/chromium/ui/base/mojo/clipboard_host.cc
@@ -33,7 +33,7 @@ void ClipboardHost::GetSequenceNumber(ClipboardType type,
void ClipboardHost::IsFormatAvailable(const std::string& format,
ClipboardType type,
IsFormatAvailableCallback callback) {
- auto format_type = Clipboard::FormatType::Deserialize(format);
+ auto format_type = ClipboardFormatType::Deserialize(format);
bool result = clipboard_->IsFormatAvailable(format_type, type);
std::move(callback).Run(result);
}
@@ -52,11 +52,11 @@ void ClipboardHost::ReadAvailableTypes(ClipboardType type,
void ClipboardHost::ReadText(ClipboardType type, ReadTextCallback callback) {
base::string16 result;
- if (clipboard_->IsFormatAvailable(Clipboard::GetPlainTextWFormatType(),
+ if (clipboard_->IsFormatAvailable(ClipboardFormatType::GetPlainTextWType(),
type)) {
clipboard_->ReadText(type, &result);
- } else if (clipboard_->IsFormatAvailable(Clipboard::GetPlainTextFormatType(),
- type)) {
+ } else if (clipboard_->IsFormatAvailable(
+ ClipboardFormatType::GetPlainTextType(), type)) {
std::string ascii;
clipboard_->ReadAsciiText(type, &ascii);
result = base::ASCIIToUTF16(ascii);
@@ -111,7 +111,7 @@ void ClipboardHost::ReadBookmark(ReadBookmarkCallback callback) {
void ClipboardHost::ReadData(const std::string& format,
ReadDataCallback callback) {
std::string result;
- clipboard_->ReadData(Clipboard::FormatType::Deserialize(format), &result);
+ clipboard_->ReadData(ClipboardFormatType::Deserialize(format), &result);
std::move(callback).Run(std::move(result));
}
diff --git a/chromium/ui/base/mojo/cursor.mojom b/chromium/ui/base/mojo/cursor.mojom
new file mode 100644
index 00000000000..6e4ea642336
--- /dev/null
+++ b/chromium/ui/base/mojo/cursor.mojom
@@ -0,0 +1,83 @@
+// 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.
+
+module ui.mojom;
+
+import "mojo/public/mojom/base/time.mojom";
+import "skia/public/interfaces/bitmap.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
+
+// Standard Cursor numbers. These are the same as Chrome's ui::Cursor and
+// blink's WebCursorInfo.
+enum CursorType {
+ // kNull is kept for compatibility with chrome declarations. In chrome code,
+ // it is treated exactly like kPointer, the default pointer.
+ kNull = 0,
+ kPointer,
+ kCross,
+ kHand,
+ kIBeam,
+ kWait,
+ kHelp,
+ kEastResize,
+ kNorthResize,
+ kNorthEastResize,
+ kNorthWestResize,
+ kSouthResize,
+ kSouthEastResize,
+ kSouthWestResize,
+ kWestResize,
+ kNorthSouthResize,
+ kEastWestResize,
+ kNorthEastSouthWestResize,
+ kNorthWestSouthEastResize,
+ kColumnResize,
+ kRowResize,
+ kMiddlePanning,
+ kEastPanning,
+ kNorthPanning,
+ kNorthEastPanning,
+ kNorthWestPanning,
+ kSouthPanning,
+ kSouthEastPanning,
+ kSouthWestPanning,
+ kWestPanning,
+ kMove,
+ kVerticalText,
+ kCell,
+ kContextMenu,
+ kAlias,
+ kProgress,
+ kNoDrop,
+ kCopy,
+ kNone,
+ kNotAllowed,
+ kZoomIn,
+ kZoomOut,
+ kGrab,
+ kGrabbing,
+ kCustom
+};
+
+// Whether we use normal or large cursors. These are the same as Chrome's
+// ui::CursorSize.
+enum CursorSize {
+ kNormal,
+ kLarge
+};
+
+// A description of a cursor.
+struct Cursor {
+ // The type of cursor. If kCustom, the rest of the fields are relevant.
+ CursorType native_type;
+
+ // The hotspot in pixels in the source cursor frames.
+ gfx.mojom.Point hotspot;
+
+ // The custom bitmap. Must be non-empty if |cursor_type| is kCustom.
+ skia.mojom.Bitmap? bitmap;
+
+ // This is the image scale of this cursor.
+ float device_scale_factor;
+};
diff --git a/chromium/ui/base/mojo/cursor.typemap b/chromium/ui/base/mojo/cursor.typemap
new file mode 100644
index 00000000000..481b16c84d4
--- /dev/null
+++ b/chromium/ui/base/mojo/cursor.typemap
@@ -0,0 +1,26 @@
+# 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.
+
+mojom = "//ui/base/mojo/cursor.mojom"
+public_headers = [
+ "//ui/base/cursor/cursor_type.h",
+ "//ui/base/cursor/cursor.h",
+]
+traits_headers = [ "//ui/base/mojo/cursor_struct_traits.h" ]
+sources = [
+ "//ui/base/mojo/cursor_struct_traits.cc",
+]
+public_deps = [
+ "//ui/base",
+]
+deps = [
+ "//ui/gfx/geometry",
+ "//ui/gfx/geometry/mojo:struct_traits",
+]
+
+type_mappings = [
+ "ui.mojom.Cursor=ui::Cursor[copyable_pass_by_value]",
+ "ui.mojom.CursorSize=ui::CursorSize",
+ "ui.mojom.CursorType=ui::CursorType",
+]
diff --git a/chromium/ui/base/mojo/cursor_struct_traits.cc b/chromium/ui/base/mojo/cursor_struct_traits.cc
new file mode 100644
index 00000000000..1620bd8cf41
--- /dev/null
+++ b/chromium/ui/base/mojo/cursor_struct_traits.cc
@@ -0,0 +1,345 @@
+// 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/mojo/cursor_struct_traits.h"
+
+#include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/mojo/cursor.mojom.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+
+namespace mojo {
+
+// static
+ui::mojom::CursorType
+EnumTraits<ui::mojom::CursorType, ui::CursorType>::ToMojom(
+ ui::CursorType input) {
+ switch (input) {
+ case ui::CursorType::kNull:
+ return ui::mojom::CursorType::kNull;
+ case ui::CursorType::kPointer:
+ return ui::mojom::CursorType::kPointer;
+ case ui::CursorType::kCross:
+ return ui::mojom::CursorType::kCross;
+ case ui::CursorType::kHand:
+ return ui::mojom::CursorType::kHand;
+ case ui::CursorType::kIBeam:
+ return ui::mojom::CursorType::kIBeam;
+ case ui::CursorType::kWait:
+ return ui::mojom::CursorType::kWait;
+ case ui::CursorType::kHelp:
+ return ui::mojom::CursorType::kHelp;
+ case ui::CursorType::kEastResize:
+ return ui::mojom::CursorType::kEastResize;
+ case ui::CursorType::kNorthResize:
+ return ui::mojom::CursorType::kNorthResize;
+ case ui::CursorType::kNorthEastResize:
+ return ui::mojom::CursorType::kNorthEastResize;
+ case ui::CursorType::kNorthWestResize:
+ return ui::mojom::CursorType::kNorthWestResize;
+ case ui::CursorType::kSouthResize:
+ return ui::mojom::CursorType::kSouthResize;
+ case ui::CursorType::kSouthEastResize:
+ return ui::mojom::CursorType::kSouthEastResize;
+ case ui::CursorType::kSouthWestResize:
+ return ui::mojom::CursorType::kSouthWestResize;
+ case ui::CursorType::kWestResize:
+ return ui::mojom::CursorType::kWestResize;
+ case ui::CursorType::kNorthSouthResize:
+ return ui::mojom::CursorType::kNorthSouthResize;
+ case ui::CursorType::kEastWestResize:
+ return ui::mojom::CursorType::kEastWestResize;
+ case ui::CursorType::kNorthEastSouthWestResize:
+ return ui::mojom::CursorType::kNorthEastSouthWestResize;
+ case ui::CursorType::kNorthWestSouthEastResize:
+ return ui::mojom::CursorType::kNorthWestSouthEastResize;
+ case ui::CursorType::kColumnResize:
+ return ui::mojom::CursorType::kColumnResize;
+ case ui::CursorType::kRowResize:
+ return ui::mojom::CursorType::kRowResize;
+ case ui::CursorType::kMiddlePanning:
+ return ui::mojom::CursorType::kMiddlePanning;
+ case ui::CursorType::kEastPanning:
+ return ui::mojom::CursorType::kEastPanning;
+ case ui::CursorType::kNorthPanning:
+ return ui::mojom::CursorType::kNorthPanning;
+ case ui::CursorType::kNorthEastPanning:
+ return ui::mojom::CursorType::kNorthEastPanning;
+ case ui::CursorType::kNorthWestPanning:
+ return ui::mojom::CursorType::kNorthWestPanning;
+ case ui::CursorType::kSouthPanning:
+ return ui::mojom::CursorType::kSouthPanning;
+ case ui::CursorType::kSouthEastPanning:
+ return ui::mojom::CursorType::kSouthEastPanning;
+ case ui::CursorType::kSouthWestPanning:
+ return ui::mojom::CursorType::kSouthWestPanning;
+ case ui::CursorType::kWestPanning:
+ return ui::mojom::CursorType::kWestPanning;
+ case ui::CursorType::kMove:
+ return ui::mojom::CursorType::kMove;
+ case ui::CursorType::kVerticalText:
+ return ui::mojom::CursorType::kVerticalText;
+ case ui::CursorType::kCell:
+ return ui::mojom::CursorType::kCell;
+ case ui::CursorType::kContextMenu:
+ return ui::mojom::CursorType::kContextMenu;
+ case ui::CursorType::kAlias:
+ return ui::mojom::CursorType::kAlias;
+ case ui::CursorType::kProgress:
+ return ui::mojom::CursorType::kProgress;
+ case ui::CursorType::kNoDrop:
+ return ui::mojom::CursorType::kNoDrop;
+ case ui::CursorType::kCopy:
+ return ui::mojom::CursorType::kCopy;
+ case ui::CursorType::kNone:
+ return ui::mojom::CursorType::kNone;
+ case ui::CursorType::kNotAllowed:
+ return ui::mojom::CursorType::kNotAllowed;
+ case ui::CursorType::kZoomIn:
+ return ui::mojom::CursorType::kZoomIn;
+ case ui::CursorType::kZoomOut:
+ return ui::mojom::CursorType::kZoomOut;
+ case ui::CursorType::kGrab:
+ return ui::mojom::CursorType::kGrab;
+ case ui::CursorType::kGrabbing:
+ return ui::mojom::CursorType::kGrabbing;
+ case ui::CursorType::kCustom:
+ return ui::mojom::CursorType::kCustom;
+ case ui::CursorType::kDndNone:
+ case ui::CursorType::kDndMove:
+ case ui::CursorType::kDndCopy:
+ case ui::CursorType::kDndLink:
+ // The mojom version is the same as the restricted Webcursor constants;
+ // don't allow system cursors to be transmitted.
+ NOTREACHED();
+ return ui::mojom::CursorType::kNull;
+ }
+ NOTREACHED();
+ return ui::mojom::CursorType::kNull;
+}
+
+// static
+bool EnumTraits<ui::mojom::CursorType, ui::CursorType>::FromMojom(
+ ui::mojom::CursorType input,
+ ui::CursorType* out) {
+ switch (input) {
+ case ui::mojom::CursorType::kNull:
+ *out = ui::CursorType::kNull;
+ return true;
+ case ui::mojom::CursorType::kPointer:
+ *out = ui::CursorType::kPointer;
+ return true;
+ case ui::mojom::CursorType::kCross:
+ *out = ui::CursorType::kCross;
+ return true;
+ case ui::mojom::CursorType::kHand:
+ *out = ui::CursorType::kHand;
+ return true;
+ case ui::mojom::CursorType::kIBeam:
+ *out = ui::CursorType::kIBeam;
+ return true;
+ case ui::mojom::CursorType::kWait:
+ *out = ui::CursorType::kWait;
+ return true;
+ case ui::mojom::CursorType::kHelp:
+ *out = ui::CursorType::kHelp;
+ return true;
+ case ui::mojom::CursorType::kEastResize:
+ *out = ui::CursorType::kEastResize;
+ return true;
+ case ui::mojom::CursorType::kNorthResize:
+ *out = ui::CursorType::kNorthResize;
+ return true;
+ case ui::mojom::CursorType::kNorthEastResize:
+ *out = ui::CursorType::kNorthEastResize;
+ return true;
+ case ui::mojom::CursorType::kNorthWestResize:
+ *out = ui::CursorType::kNorthWestResize;
+ return true;
+ case ui::mojom::CursorType::kSouthResize:
+ *out = ui::CursorType::kSouthResize;
+ return true;
+ case ui::mojom::CursorType::kSouthEastResize:
+ *out = ui::CursorType::kSouthEastResize;
+ return true;
+ case ui::mojom::CursorType::kSouthWestResize:
+ *out = ui::CursorType::kSouthWestResize;
+ return true;
+ case ui::mojom::CursorType::kWestResize:
+ *out = ui::CursorType::kWestResize;
+ return true;
+ case ui::mojom::CursorType::kNorthSouthResize:
+ *out = ui::CursorType::kNorthSouthResize;
+ return true;
+ case ui::mojom::CursorType::kEastWestResize:
+ *out = ui::CursorType::kEastWestResize;
+ return true;
+ case ui::mojom::CursorType::kNorthEastSouthWestResize:
+ *out = ui::CursorType::kNorthEastSouthWestResize;
+ return true;
+ case ui::mojom::CursorType::kNorthWestSouthEastResize:
+ *out = ui::CursorType::kNorthWestSouthEastResize;
+ return true;
+ case ui::mojom::CursorType::kColumnResize:
+ *out = ui::CursorType::kColumnResize;
+ return true;
+ case ui::mojom::CursorType::kRowResize:
+ *out = ui::CursorType::kRowResize;
+ return true;
+ case ui::mojom::CursorType::kMiddlePanning:
+ *out = ui::CursorType::kMiddlePanning;
+ return true;
+ case ui::mojom::CursorType::kEastPanning:
+ *out = ui::CursorType::kEastPanning;
+ return true;
+ case ui::mojom::CursorType::kNorthPanning:
+ *out = ui::CursorType::kNorthPanning;
+ return true;
+ case ui::mojom::CursorType::kNorthEastPanning:
+ *out = ui::CursorType::kNorthEastPanning;
+ return true;
+ case ui::mojom::CursorType::kNorthWestPanning:
+ *out = ui::CursorType::kNorthWestPanning;
+ return true;
+ case ui::mojom::CursorType::kSouthPanning:
+ *out = ui::CursorType::kSouthPanning;
+ return true;
+ case ui::mojom::CursorType::kSouthEastPanning:
+ *out = ui::CursorType::kSouthEastPanning;
+ return true;
+ case ui::mojom::CursorType::kSouthWestPanning:
+ *out = ui::CursorType::kSouthWestPanning;
+ return true;
+ case ui::mojom::CursorType::kWestPanning:
+ *out = ui::CursorType::kWestPanning;
+ return true;
+ case ui::mojom::CursorType::kMove:
+ *out = ui::CursorType::kMove;
+ return true;
+ case ui::mojom::CursorType::kVerticalText:
+ *out = ui::CursorType::kVerticalText;
+ return true;
+ case ui::mojom::CursorType::kCell:
+ *out = ui::CursorType::kCell;
+ return true;
+ case ui::mojom::CursorType::kContextMenu:
+ *out = ui::CursorType::kContextMenu;
+ return true;
+ case ui::mojom::CursorType::kAlias:
+ *out = ui::CursorType::kAlias;
+ return true;
+ case ui::mojom::CursorType::kProgress:
+ *out = ui::CursorType::kProgress;
+ return true;
+ case ui::mojom::CursorType::kNoDrop:
+ *out = ui::CursorType::kNoDrop;
+ return true;
+ case ui::mojom::CursorType::kCopy:
+ *out = ui::CursorType::kCopy;
+ return true;
+ case ui::mojom::CursorType::kNone:
+ *out = ui::CursorType::kNone;
+ return true;
+ case ui::mojom::CursorType::kNotAllowed:
+ *out = ui::CursorType::kNotAllowed;
+ return true;
+ case ui::mojom::CursorType::kZoomIn:
+ *out = ui::CursorType::kZoomIn;
+ return true;
+ case ui::mojom::CursorType::kZoomOut:
+ *out = ui::CursorType::kZoomOut;
+ return true;
+ case ui::mojom::CursorType::kGrab:
+ *out = ui::CursorType::kGrab;
+ return true;
+ case ui::mojom::CursorType::kGrabbing:
+ *out = ui::CursorType::kGrabbing;
+ return true;
+ case ui::mojom::CursorType::kCustom:
+ *out = ui::CursorType::kCustom;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
+ui::mojom::CursorSize
+EnumTraits<ui::mojom::CursorSize, ui::CursorSize>::ToMojom(
+ ui::CursorSize input) {
+ switch (input) {
+ case ui::CursorSize::kNormal:
+ return ui::mojom::CursorSize::kNormal;
+ case ui::CursorSize::kLarge:
+ return ui::mojom::CursorSize::kLarge;
+ }
+
+ NOTREACHED();
+ return ui::mojom::CursorSize::kNormal;
+}
+
+// static
+bool EnumTraits<ui::mojom::CursorSize, ui::CursorSize>::FromMojom(
+ ui::mojom::CursorSize input,
+ ui::CursorSize* out) {
+ switch (input) {
+ case ui::mojom::CursorSize::kNormal:
+ *out = ui::CursorSize::kNormal;
+ return true;
+ case ui::mojom::CursorSize::kLarge:
+ *out = ui::CursorSize::kLarge;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
+gfx::Point StructTraits<ui::mojom::CursorDataView, ui::Cursor>::hotspot(
+ const ui::Cursor& c) {
+ return c.GetHotspot();
+}
+
+// static
+SkBitmap StructTraits<ui::mojom::CursorDataView, ui::Cursor>::bitmap(
+ const ui::Cursor& c) {
+ return c.GetBitmap();
+}
+
+// static
+bool StructTraits<ui::mojom::CursorDataView, ui::Cursor>::Read(
+ ui::mojom::CursorDataView data,
+ ui::Cursor* out) {
+ ui::CursorType type;
+ if (!data.ReadNativeType(&type))
+ return false;
+
+ if (type != ui::CursorType::kCustom) {
+ *out = ui::Cursor(type);
+ return true;
+ }
+
+ gfx::Point hotspot;
+ SkBitmap bitmap;
+
+ if (!data.ReadHotspot(&hotspot) || !data.ReadBitmap(&bitmap))
+ return false;
+
+ // Clamp the scale factor to a reasonable value. TODO(estade): do we even need
+ // this field? It doesn't appear to be used anywhere and is a property of the
+ // display, not the cursor.
+ float device_scale_factor = data.device_scale_factor();
+ if (device_scale_factor < 1.f || device_scale_factor > 3.f)
+ return false;
+
+ *out = ui::Cursor(type);
+ out->set_custom_bitmap(bitmap);
+ out->set_custom_hotspot(hotspot);
+ out->set_device_scale_factor(device_scale_factor);
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/ui/base/mojo/cursor_struct_traits.h b/chromium/ui/base/mojo/cursor_struct_traits.h
new file mode 100644
index 00000000000..a82816698f3
--- /dev/null
+++ b/chromium/ui/base/mojo/cursor_struct_traits.h
@@ -0,0 +1,41 @@
+// 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_MOJO_CURSOR_STRUCT_TRAITS_H_
+#define UI_BASE_MOJO_CURSOR_STRUCT_TRAITS_H_
+
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/cursor_type.h"
+#include "ui/base/mojo/cursor.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<ui::mojom::CursorType, ui::CursorType> {
+ static ui::mojom::CursorType ToMojom(ui::CursorType input);
+ static bool FromMojom(ui::mojom::CursorType input, ui::CursorType* out);
+};
+
+template <>
+struct EnumTraits<ui::mojom::CursorSize, ui::CursorSize> {
+ static ui::mojom::CursorSize ToMojom(ui::CursorSize input);
+ static bool FromMojom(ui::mojom::CursorSize input, ui::CursorSize* out);
+};
+
+template <>
+struct StructTraits<ui::mojom::CursorDataView, ui::Cursor> {
+ static ui::CursorType native_type(const ui::Cursor& c) {
+ return c.native_type();
+ }
+ static gfx::Point hotspot(const ui::Cursor& c);
+ static SkBitmap bitmap(const ui::Cursor& c);
+ static float device_scale_factor(const ui::Cursor& c) {
+ return c.device_scale_factor();
+ }
+ static bool Read(ui::mojom::CursorDataView data, ui::Cursor* out);
+};
+
+} // namespace mojo
+
+#endif // UI_BASE_MOJO_CURSOR_STRUCT_TRAITS_H_
diff --git a/chromium/ui/base/mojo/cursor_struct_traits_unittest.cc b/chromium/ui/base/mojo/cursor_struct_traits_unittest.cc
new file mode 100644
index 00000000000..15104717579
--- /dev/null
+++ b/chromium/ui/base/mojo/cursor_struct_traits_unittest.cc
@@ -0,0 +1,98 @@
+// 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/mojo/cursor_struct_traits.h"
+
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/mojo/cursor.mojom.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+
+namespace ui {
+
+namespace {
+
+bool EchoCursor(const ui::Cursor& in, ui::Cursor* out) {
+ return mojom::Cursor::Deserialize(mojom::Cursor::Serialize(&in), out);
+}
+
+using CursorStructTraitsTest = testing::Test;
+
+} // namespace
+
+// Tests numeric cursor ids.
+TEST_F(CursorStructTraitsTest, TestBuiltIn) {
+ for (int i = 0; i < 43; ++i) {
+ ui::CursorType type = static_cast<ui::CursorType>(i);
+ ui::Cursor input(type);
+
+ ui::Cursor output;
+ ASSERT_TRUE(EchoCursor(input, &output));
+ EXPECT_EQ(type, output.native_type());
+ }
+}
+
+// Test that we copy cursor bitmaps and metadata across the wire.
+TEST_F(CursorStructTraitsTest, TestBitmapCursor) {
+ ui::Cursor input(ui::CursorType::kCustom);
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(10, 10);
+ bitmap.eraseColor(SK_ColorRED);
+
+ const gfx::Point kHotspot = gfx::Point(5, 2);
+ input.set_custom_hotspot(kHotspot);
+ input.set_custom_bitmap(bitmap);
+
+ const float kScale = 2.0f;
+ input.set_device_scale_factor(kScale);
+
+ ui::Cursor output;
+ ASSERT_TRUE(EchoCursor(input, &output));
+
+ EXPECT_EQ(ui::CursorType::kCustom, output.native_type());
+ EXPECT_EQ(kScale, output.device_scale_factor());
+ EXPECT_EQ(kHotspot, output.GetHotspot());
+
+ // Even if the pixel data is logically the same, expect that it has different
+ // generation ids.
+ EXPECT_FALSE(output.IsSameAs(input));
+
+ // Make a copy of output. It should be the same as output.
+ ui::Cursor copy = output;
+ EXPECT_TRUE(copy.IsSameAs(output));
+
+ // But make sure that the pixel data actually is equivalent.
+ ASSERT_EQ(input.GetBitmap().width(), output.GetBitmap().width());
+ ASSERT_EQ(input.GetBitmap().height(), output.GetBitmap().height());
+
+ for (int x = 0; x < input.GetBitmap().width(); ++x) {
+ for (int y = 0; y < input.GetBitmap().height(); ++y) {
+ EXPECT_EQ(input.GetBitmap().getColor(x, y),
+ output.GetBitmap().getColor(x, y));
+ }
+ }
+}
+
+// Test that we deal with empty bitmaps. (When a cursor resource isn't loaded
+// in the renderer, the renderer will send a custom cursor with an empty
+// bitmap.)
+TEST_F(CursorStructTraitsTest, TestEmptyCursor) {
+ const gfx::Point kHotspot = gfx::Point(5, 2);
+ const float kScale = 2.0f;
+
+ ui::Cursor input(ui::CursorType::kCustom);
+ input.set_custom_hotspot(kHotspot);
+ input.set_custom_bitmap(SkBitmap());
+ input.set_device_scale_factor(kScale);
+
+ ui::Cursor output;
+ ASSERT_TRUE(EchoCursor(input, &output));
+
+ EXPECT_TRUE(output.GetBitmap().empty());
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/mojo/typemaps.gni b/chromium/ui/base/mojo/typemaps.gni
index a4c8c0ef232..5f970ce5bae 100644
--- a/chromium/ui/base/mojo/typemaps.gni
+++ b/chromium/ui/base/mojo/typemaps.gni
@@ -5,6 +5,7 @@
typemaps = [
"//ui/base/mojo/clipboard.typemap",
"//ui/base/mojo/clipboard_blink.typemap",
+ "//ui/base/mojo/cursor.typemap",
"//ui/base/mojo/ui_base_types.typemap",
"//ui/base/mojo/window_open_disposition.typemap",
]
diff --git a/chromium/ui/base/resource/resource_bundle.cc b/chromium/ui/base/resource/resource_bundle.cc
index c371212e0ce..340291d8c8f 100644
--- a/chromium/ui/base/resource/resource_bundle.cc
+++ b/chromium/ui/base/resource/resource_bundle.cc
@@ -15,7 +15,6 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/path_service.h"
#include "base/stl_util.h"
@@ -28,12 +27,12 @@
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/layout.h"
#include "ui/base/resource/data_pack.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/ui_base_switches.h"
-#include "ui/base/ui_features.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/codec/jpeg_codec.h"
@@ -153,23 +152,28 @@ class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
};
struct ResourceBundle::FontKey {
- FontKey(int in_size_delta,
+ FontKey(const std::string& typeface,
+ int in_size_delta,
gfx::Font::FontStyle in_style,
gfx::Font::Weight in_weight)
- : size_delta(in_size_delta), style(in_style), weight(in_weight) {}
+ : typeface(typeface),
+ size_delta(in_size_delta),
+ style(in_style),
+ weight(in_weight) {}
~FontKey() {}
bool operator==(const FontKey& rhs) const {
- return std::tie(size_delta, style, weight) ==
- std::tie(rhs.size_delta, rhs.style, rhs.weight);
+ return std::tie(typeface, size_delta, style, weight) ==
+ std::tie(rhs.typeface, rhs.size_delta, rhs.style, rhs.weight);
}
bool operator<(const FontKey& rhs) const {
- return std::tie(size_delta, style, weight) <
- std::tie(rhs.size_delta, rhs.style, rhs.weight);
+ return std::tie(typeface, size_delta, style, weight) <
+ std::tie(rhs.typeface, rhs.size_delta, rhs.style, rhs.weight);
}
+ std::string typeface;
int size_delta;
gfx::Font::FontStyle style;
gfx::Font::Weight weight;
@@ -591,16 +595,34 @@ const gfx::FontList& ResourceBundle::GetFontListWithDelta(
int size_delta,
gfx::Font::FontStyle style,
gfx::Font::Weight weight) {
+ return GetFontListWithTypefaceAndDelta(/*typeface=*/std::string(), size_delta,
+ style, weight);
+}
+
+const gfx::FontList& ResourceBundle::GetFontListWithTypefaceAndDelta(
+ const std::string& typeface,
+ int size_delta,
+ gfx::Font::FontStyle style,
+ gfx::Font::Weight weight) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- const FontKey styled_key(size_delta, style, weight);
+ const FontKey styled_key(typeface, size_delta, style, weight);
auto found = font_cache_.find(styled_key);
if (found != font_cache_.end())
return found->second;
- const FontKey base_key(0, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
- gfx::FontList& base = font_cache_[base_key];
+ const FontKey base_key(typeface, 0, gfx::Font::NORMAL,
+ gfx::Font::Weight::NORMAL);
+ gfx::FontList default_font_list = gfx::FontList();
+ gfx::FontList base_font_list =
+ typeface.empty()
+ ? default_font_list
+ : gfx::FontList({typeface}, default_font_list.GetFontStyle(),
+ default_font_list.GetFontSize(),
+ default_font_list.GetFontWeight());
+ font_cache_.insert({base_key, base_font_list});
+ gfx::FontList& base = font_cache_.find(base_key)->second;
if (styled_key == base_key)
return base;
@@ -608,15 +630,16 @@ const gfx::FontList& ResourceBundle::GetFontListWithDelta(
// Cache the unstyled font by first inserting a default-constructed font list.
// Then, derive it for the initial insertion, or use the iterator that points
// to the existing entry that the insertion collided with.
- const FontKey sized_key(size_delta, gfx::Font::NORMAL,
+ const FontKey sized_key(typeface, size_delta, gfx::Font::NORMAL,
gfx::Font::Weight::NORMAL);
- auto sized = font_cache_.insert(std::make_pair(sized_key, gfx::FontList()));
+ auto sized = font_cache_.insert(std::make_pair(sized_key, base_font_list));
if (sized.second)
sized.first->second = base.DeriveWithSizeDelta(size_delta);
- if (styled_key == sized_key)
+ if (styled_key == sized_key) {
return sized.first->second;
+ }
- auto styled = font_cache_.insert(std::make_pair(styled_key, gfx::FontList()));
+ auto styled = font_cache_.insert(std::make_pair(styled_key, base_font_list));
DCHECK(styled.second); // Otherwise font_cache_.find(..) would have found it.
styled.first->second = sized.first->second.Derive(
0, sized.first->second.GetFontStyle() | style, weight);
@@ -940,12 +963,12 @@ base::string16 ResourceBundle::GetLocalizedStringImpl(int resource_id) {
// static
bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf,
size_t size) {
- if (size < arraysize(kPngMagic) ||
- memcmp(buf, kPngMagic, arraysize(kPngMagic)) != 0) {
+ if (size < base::size(kPngMagic) ||
+ memcmp(buf, kPngMagic, base::size(kPngMagic)) != 0) {
// Data invalid or a JPEG.
return false;
}
- size_t pos = arraysize(kPngMagic);
+ size_t pos = base::size(kPngMagic);
// Scan for custom chunks until we find one, find the IDAT chunk, or run out
// of chunks.
@@ -956,13 +979,12 @@ bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf,
base::ReadBigEndian(reinterpret_cast<const char*>(buf + pos), &length);
if (size - pos - kPngChunkMetadataSize < length)
break;
- if (length == 0 &&
- memcmp(buf + pos + sizeof(uint32_t), kPngScaleChunkType,
- arraysize(kPngScaleChunkType)) == 0) {
+ if (length == 0 && memcmp(buf + pos + sizeof(uint32_t), kPngScaleChunkType,
+ base::size(kPngScaleChunkType)) == 0) {
return true;
}
if (memcmp(buf + pos + sizeof(uint32_t), kPngDataChunkType,
- arraysize(kPngDataChunkType)) == 0) {
+ base::size(kPngDataChunkType)) == 0) {
// Stop looking for custom chunks, any custom chunks should be before an
// IDAT chunk.
break;
diff --git a/chromium/ui/base/resource/resource_bundle.h b/chromium/ui/base/resource/resource_bundle.h
index c24fcf0ba3c..1f0f0b575e4 100644
--- a/chromium/ui/base/resource/resource_bundle.h
+++ b/chromium/ui/base/resource/resource_bundle.h
@@ -10,9 +10,9 @@
#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
-#include "base/containers/hash_tables.h"
#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
#include "base/gtest_prod_util.h"
@@ -252,6 +252,16 @@ class UI_BASE_EXPORT ResourceBundle {
gfx::Font::FontStyle style = gfx::Font::NORMAL,
gfx::Font::Weight weight = gfx::Font::Weight::NORMAL);
+ // Returns a font list derived from the user-specified typeface. The
+ // result is always cached and exists for the lifetime of the process.
+ // If typeface is empty, we default to the platform-specific "Base" font
+ // list.
+ const gfx::FontList& GetFontListWithTypefaceAndDelta(
+ const std::string& typeface,
+ int size_delta,
+ gfx::Font::FontStyle style = gfx::Font::NORMAL,
+ gfx::Font::Weight weight = gfx::Font::Weight::NORMAL);
+
// Returns the primary font from the FontList given by GetFontListWithDelta().
const gfx::Font& GetFontWithDelta(
int size_delta,
@@ -324,7 +334,7 @@ class UI_BASE_EXPORT ResourceBundle {
struct FontKey;
- using IdToStringMap = base::hash_map<int, base::string16>;
+ using IdToStringMap = std::unordered_map<int, base::string16>;
// Ctor/dtor are private, since we're a singleton.
explicit ResourceBundle(Delegate* delegate);
diff --git a/chromium/ui/base/resource/resource_bundle_android.cc b/chromium/ui/base/resource/resource_bundle_android.cc
index 5fdfaeae0e7..899bb583517 100644
--- a/chromium/ui/base/resource/resource_bundle_android.cc
+++ b/chromium/ui/base/resource/resource_bundle_android.cc
@@ -8,6 +8,7 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "jni/ResourceBundle_jni.h"
#include "ui/base/l10n/l10n_util.h"
@@ -77,19 +78,30 @@ std::unique_ptr<DataPack> LoadDataPackFromLocalePak(
return data_pack;
}
+enum class LoadFailureReason {
+ kLocalePakNotFound,
+ kPackLoadFailedPrimary,
+ kPackLoadFailedSecondary,
+ kMaxValue = kPackLoadFailedSecondary,
+};
+
+void LogLoadLocaleFailureReason(LoadFailureReason reason) {
+ UMA_HISTOGRAM_ENUMERATION("Android.ResourceBundle.LoadLocaleFailure", reason);
+}
+
} // namespace
void ResourceBundle::LoadCommonResources() {
base::FilePath disk_path;
base::PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &disk_path);
disk_path = disk_path.AppendASCII("chrome_100_percent.pak");
- if (LoadFromApkOrFile("assets/chrome_100_percent.pak",
- &disk_path,
- &g_chrome_100_percent_fd,
- &g_chrome_100_percent_region)) {
- AddDataPackFromFileRegion(base::File(g_chrome_100_percent_fd),
- g_chrome_100_percent_region, SCALE_FACTOR_100P);
- }
+ bool success =
+ LoadFromApkOrFile("assets/chrome_100_percent.pak", &disk_path,
+ &g_chrome_100_percent_fd, &g_chrome_100_percent_region);
+ DCHECK(success);
+
+ AddDataPackFromFileRegion(base::File(g_chrome_100_percent_fd),
+ g_chrome_100_percent_region, SCALE_FACTOR_100P);
}
// static
@@ -122,6 +134,7 @@ std::string ResourceBundle::LoadLocaleResources(
if (locale_file_path.empty()) {
// It's possible that there is no locale.pak.
LOG(WARNING) << "locale_file_path.empty() for locale " << app_locale;
+ LogLoadLocaleFailureReason(LoadFailureReason::kLocalePakNotFound);
return std::string();
}
int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
@@ -132,8 +145,10 @@ std::string ResourceBundle::LoadLocaleResources(
locale_resources_data_ = LoadDataPackFromLocalePak(
g_locale_pack_fd, g_locale_pack_region);
- if (!locale_resources_data_.get())
+ if (!locale_resources_data_.get()) {
+ LogLoadLocaleFailureReason(LoadFailureReason::kPackLoadFailedPrimary);
return std::string();
+ }
// Load secondary locale .pak file if it exists. For debug build monochrome,
// a secondary locale pak will always be loaded; however, it should be
@@ -146,8 +161,10 @@ std::string ResourceBundle::LoadLocaleResources(
secondary_locale_resources_data_ = LoadDataPackFromLocalePak(
g_secondary_locale_pack_fd, g_secondary_locale_pack_region);
- if (!secondary_locale_resources_data_.get())
+ if (!secondary_locale_resources_data_.get()) {
+ LogLoadLocaleFailureReason(LoadFailureReason::kPackLoadFailedSecondary);
return std::string();
+ }
}
return app_locale;
diff --git a/chromium/ui/base/resource/resource_bundle_unittest.cc b/chromium/ui/base/resource/resource_bundle_unittest.cc
index 710b274ef59..e2e69d34371 100644
--- a/chromium/ui/base/resource/resource_bundle_unittest.cc
+++ b/chromium/ui/base/resource/resource_bundle_unittest.cc
@@ -14,8 +14,8 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -87,12 +87,11 @@ class MockResourceBundleDelegate : public ui::ResourceBundle::Delegate {
// Returns |bitmap_data| with |custom_chunk| inserted after the IHDR chunk.
void AddCustomChunk(const base::StringPiece& custom_chunk,
std::vector<unsigned char>* bitmap_data) {
- EXPECT_LT(arraysize(kPngMagic) + kPngChunkMetadataSize, bitmap_data->size());
- EXPECT_TRUE(std::equal(
- bitmap_data->begin(),
- bitmap_data->begin() + arraysize(kPngMagic),
- kPngMagic));
- auto ihdr_start = bitmap_data->begin() + arraysize(kPngMagic);
+ EXPECT_LT(base::size(kPngMagic) + kPngChunkMetadataSize, bitmap_data->size());
+ EXPECT_TRUE(std::equal(bitmap_data->begin(),
+ bitmap_data->begin() + base::size(kPngMagic),
+ kPngMagic));
+ auto ihdr_start = bitmap_data->begin() + base::size(kPngMagic);
char ihdr_length_data[sizeof(uint32_t)];
for (size_t i = 0; i < sizeof(uint32_t); ++i)
ihdr_length_data[i] = *(ihdr_start + i);
@@ -516,9 +515,10 @@ TEST_F(ResourceBundleImageTest, GetImageNamedFallback1x) {
CreateDataPackWithSingleBitmap(data_path, 10, base::StringPiece());
// 2x data pack bitmap has custom chunk to indicate that the 2x bitmap is not
// available and that GRIT fell back to 1x.
- CreateDataPackWithSingleBitmap(data_2x_path, 10, base::StringPiece(
- reinterpret_cast<const char*>(kPngScaleChunk),
- arraysize(kPngScaleChunk)));
+ CreateDataPackWithSingleBitmap(
+ data_2x_path, 10,
+ base::StringPiece(reinterpret_cast<const char*>(kPngScaleChunk),
+ base::size(kPngScaleChunk)));
// Load the regular and 2x pak files.
ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
@@ -554,12 +554,14 @@ TEST_F(ResourceBundleImageTest, GetImageNamedFallback1xRounding) {
CreateDataPackWithSingleBitmap(data_path, 8, base::StringPiece());
// Mark 140% and 180% images as requiring 1x fallback.
- CreateDataPackWithSingleBitmap(data_140P_path, 8, base::StringPiece(
- reinterpret_cast<const char*>(kPngScaleChunk),
- arraysize(kPngScaleChunk)));
- CreateDataPackWithSingleBitmap(data_180P_path, 8, base::StringPiece(
- reinterpret_cast<const char*>(kPngScaleChunk),
- arraysize(kPngScaleChunk)));
+ CreateDataPackWithSingleBitmap(
+ data_140P_path, 8,
+ base::StringPiece(reinterpret_cast<const char*>(kPngScaleChunk),
+ base::size(kPngScaleChunk)));
+ CreateDataPackWithSingleBitmap(
+ data_180P_path, 8,
+ base::StringPiece(reinterpret_cast<const char*>(kPngScaleChunk),
+ base::size(kPngScaleChunk)));
ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
diff --git a/chromium/ui/base/resource/scale_factor.cc b/chromium/ui/base/resource/scale_factor.cc
index dceffaec424..aa52f48804e 100644
--- a/chromium/ui/base/resource/scale_factor.cc
+++ b/chromium/ui/base/resource/scale_factor.cc
@@ -4,7 +4,7 @@
#include "ui/base/resource/scale_factor.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
namespace ui {
@@ -12,7 +12,7 @@ namespace {
const float kScaleFactorScales[] = {1.0f, 1.0f, 1.25f, 1.33f, 1.4f, 1.5f, 1.8f,
2.0f, 2.5f, 3.0f};
-static_assert(NUM_SCALE_FACTORS == arraysize(kScaleFactorScales),
+static_assert(NUM_SCALE_FACTORS == base::size(kScaleFactorScales),
"kScaleFactorScales has incorrect size");
} // namespace
diff --git a/chromium/ui/base/template_expressions.cc b/chromium/ui/base/template_expressions.cc
index 1aec20cb5b9..fbbeb320a3d 100644
--- a/chromium/ui/base/template_expressions.cc
+++ b/chromium/ui/base/template_expressions.cc
@@ -7,12 +7,13 @@
#include <stddef.h>
#include "base/logging.h"
+#include "base/stl_util.h"
#include "base/values.h"
#include "net/base/escape.h"
namespace {
const char kLeader[] = "$i18n";
-const size_t kLeaderSize = arraysize(kLeader) - 1;
+const size_t kLeaderSize = base::size(kLeader) - 1;
const char kKeyOpen = '{';
const char kKeyClose = '}';
diff --git a/chromium/ui/base/text/bytes_formatting.cc b/chromium/ui/base/text/bytes_formatting.cc
index aff188c2cb8..4596414cfb8 100644
--- a/chromium/ui/base/text/bytes_formatting.cc
+++ b/chromium/ui/base/text/bytes_formatting.cc
@@ -6,7 +6,7 @@
#include "base/i18n/number_formatting.h"
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
@@ -82,7 +82,7 @@ DataUnits GetByteDisplayUnits(int64_t bytes) {
return DATA_UNITS_BYTE;
}
- int unit_index = arraysize(kUnitThresholds);
+ int unit_index = base::size(kUnitThresholds);
while (--unit_index > 0) {
if (bytes >= kUnitThresholds[unit_index])
break;
diff --git a/chromium/ui/base/text/bytes_formatting_unittest.cc b/chromium/ui/base/text/bytes_formatting_unittest.cc
index b2c2a410a5c..eba175478a8 100644
--- a/chromium/ui/base/text/bytes_formatting_unittest.cc
+++ b/chromium/ui/base/text/bytes_formatting_unittest.cc
@@ -5,7 +5,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/text/bytes_formatting.h"
@@ -29,7 +29,7 @@ TEST(BytesFormattingTest, GetByteDisplayUnits) {
#endif
};
- for (size_t i = 0; i < arraysize(cases); ++i)
+ for (size_t i = 0; i < base::size(cases); ++i)
EXPECT_EQ(cases[i].expected, GetByteDisplayUnits(cases[i].bytes));
}
@@ -72,7 +72,7 @@ TEST(BytesFormattingTest, FormatBytes) {
#endif
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
EXPECT_EQ(base::ASCIIToUTF16(cases[i].expected),
FormatBytesWithUnits(cases[i].bytes, cases[i].units, false));
EXPECT_EQ(base::ASCIIToUTF16(cases[i].expected_with_units),
diff --git a/chromium/ui/base/ui_base_features.cc b/chromium/ui/base/ui_base_features.cc
index 548c51dc17f..71bd2fbcf77 100644
--- a/chromium/ui/base/ui_base_features.cc
+++ b/chromium/ui/base/ui_base_features.cc
@@ -17,16 +17,6 @@ namespace features {
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 {
- "EnableEmojiContextMenu",
-#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_CHROMEOS)
- base::FEATURE_ENABLED_BY_DEFAULT
-#else
- base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-};
// Enables the full screen handwriting virtual keyboard behavior.
const base::Feature kEnableFullscreenHandwritingVirtualKeyboard = {
@@ -59,14 +49,6 @@ const base::Feature kInputMethodSettingsUiUpdate = {
const base::Feature kSystemKeyboardLock{"SystemKeyboardLock",
base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kTouchableAppContextMenu = {
- "EnableTouchableAppContextMenu", base::FEATURE_ENABLED_BY_DEFAULT};
-
-bool IsTouchableAppContextMenuEnabled() {
- return base::FeatureList::IsEnabled(kTouchableAppContextMenu) ||
- switches::IsTouchableAppContextMenuEnabled();
-}
-
const base::Feature kNotificationIndicator = {
"EnableNotificationIndicator", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -101,7 +83,7 @@ const base::Feature kUiCompositorScrollWithLayers = {
#if defined(OS_WIN)
// Enables InputPane API for controlling on screen keyboard.
const base::Feature kInputPaneOnScreenKeyboard = {
- "InputPaneOnScreenKeyboard", base::FEATURE_DISABLED_BY_DEFAULT};
+ "InputPaneOnScreenKeyboard", base::FEATURE_ENABLED_BY_DEFAULT};
// Enables using WM_POINTER instead of WM_TOUCH for touch events.
const base::Feature kPointerEventsForTouch = {"PointerEventsForTouch",
@@ -162,7 +144,8 @@ bool IsMashOopVizEnabled() {
}
bool IsSingleProcessMash() {
- return base::FeatureList::IsEnabled(features::kSingleProcessMash);
+ return base::FeatureList::IsEnabled(features::kSingleProcessMash) &&
+ !base::FeatureList::IsEnabled(features::kMash);
}
bool IsAutomaticUiAdjustmentsForTouchEnabled() {
@@ -178,7 +161,7 @@ bool IsAutomaticUiAdjustmentsForTouchEnabled() {
// When enabled, the NSWindows for apps will be created in the app's process,
// and will forward input to the browser process.
const base::Feature kHostWindowsInAppShimProcess{
- "HostWindowsInAppShimProcess", base::FEATURE_DISABLED_BY_DEFAULT};
+ "HostWindowsInAppShimProcess", base::FEATURE_ENABLED_BY_DEFAULT};
bool HostWindowsInAppShimProcess() {
return base::FeatureList::IsEnabled(kHostWindowsInAppShimProcess);
@@ -195,4 +178,8 @@ bool IsOzoneDrmMojo() {
const base::Feature kDarkMode = {"DarkMode", base::FEATURE_DISABLED_BY_DEFAULT};
+#if defined(OS_CHROMEOS)
+const base::Feature kHandwritingGesture = {"HandwritingGesture",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
} // namespace features
diff --git a/chromium/ui/base/ui_base_features.h b/chromium/ui/base/ui_base_features.h
index 2a3e2546039..614dc06595d 100644
--- a/chromium/ui/base/ui_base_features.h
+++ b/chromium/ui/base/ui_base_features.h
@@ -7,13 +7,12 @@
#include "base/feature_list.h"
#include "build/build_config.h"
+#include "ui/base/buildflags.h"
#include "ui/base/ui_base_export.h"
-#include "ui/base/ui_features.h"
namespace features {
// Keep sorted!
-UI_BASE_EXPORT extern const base::Feature kEnableEmojiContextMenu;
UI_BASE_EXPORT extern const base::Feature
kEnableFullscreenHandwritingVirtualKeyboard;
UI_BASE_EXPORT extern const base::Feature kEnableStylusVirtualKeyboard;
@@ -24,11 +23,9 @@ 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;
UI_BASE_EXPORT extern const base::Feature kUiCompositorScrollWithLayers;
-UI_BASE_EXPORT bool IsTouchableAppContextMenuEnabled();
UI_BASE_EXPORT bool IsNotificationIndicatorEnabled();
UI_BASE_EXPORT bool IsUiGpuRasterizationEnabled();
@@ -63,6 +60,8 @@ UI_BASE_EXPORT extern const base::Feature kMash;
// make it the default kMash behavior.
UI_BASE_EXPORT extern const base::Feature kMashOopViz;
+// NOTE: Do not access directly outside of tests. Use IsSingleProcessMash()
+// to avoid problems when Mash and SingleProcessMash are both enabled.
UI_BASE_EXPORT extern const base::Feature kSingleProcessMash;
// Returns true if Chrome's aura usage is backed by the WindowService.
@@ -104,6 +103,9 @@ UI_BASE_EXPORT bool IsOzoneDrmMojo();
// macOS Mojave/Windows 10.
UI_BASE_EXPORT extern const base::Feature kDarkMode;
+#if defined(OS_CHROMEOS)
+UI_BASE_EXPORT extern const base::Feature kHandwritingGesture;
+#endif
} // namespace features
#endif // UI_BASE_UI_BASE_FEATURES_H_
diff --git a/chromium/ui/base/ui_base_switches.cc b/chromium/ui/base/ui_base_switches.cc
index 99cd8eac41d..c2d4f252d6f 100644
--- a/chromium/ui/base/ui_base_switches.cc
+++ b/chromium/ui/base/ui_base_switches.cc
@@ -48,6 +48,9 @@ const char kEnableTouchDragDrop[] = "enable-touch-drag-drop";
const char kEnableTouchableAppContextMenu[] =
"enable-touchable-app-context-menus";
+// Forces the caption style for WebVTT captions.
+const char kForceCaptionStyle[] = "force-caption-style";
+
// Forces dark mode in UI for platforms that support it.
const char kForceDarkMode[] = "force-dark-mode";
diff --git a/chromium/ui/base/ui_base_switches.h b/chromium/ui/base/ui_base_switches.h
index 0ac60c1cd6b..2162f1e1f98 100644
--- a/chromium/ui/base/ui_base_switches.h
+++ b/chromium/ui/base/ui_base_switches.h
@@ -27,6 +27,7 @@ UI_BASE_EXPORT extern const char kDisableTouchAdjustment[];
UI_BASE_EXPORT extern const char kDisableTouchDragDrop[];
UI_BASE_EXPORT extern const char kEnableTouchDragDrop[];
UI_BASE_EXPORT extern const char kEnableTouchableAppContextMenu[];
+UI_BASE_EXPORT extern const char kForceCaptionStyle[];
UI_BASE_EXPORT extern const char kForceDarkMode[];
UI_BASE_EXPORT extern const char kForceHighContrast[];
UI_BASE_EXPORT extern const char kLang[];
diff --git a/chromium/ui/base/x/selection_owner.cc b/chromium/ui/base/x/selection_owner.cc
index 1804eaedee8..4efee2d2554 100644
--- a/chromium/ui/base/x/selection_owner.cc
+++ b/chromium/ui/base/x/selection_owner.cc
@@ -54,7 +54,7 @@ bool GetAtomPairArrayProperty(XID window,
XAtom type = x11::None;
int format = 0; // size in bits of each item in 'property'
unsigned long num_items = 0;
- unsigned char* properties = NULL;
+ unsigned char* properties = nullptr;
unsigned long remaining_bytes = 0;
int result = XGetWindowProperty(gfx::GetXDisplay(), window, property,
@@ -100,9 +100,8 @@ SelectionOwner::~SelectionOwner() {
}
void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) {
- for (auto it = format_map_.begin(); it != format_map_.end(); ++it) {
- targets->push_back(it->first);
- }
+ for (const auto& format_target : format_map_)
+ targets->push_back(format_target.first);
}
void SelectionOwner::TakeOwnershipOfSelection(
@@ -145,13 +144,12 @@ void SelectionOwner::OnSelectionRequest(const XEvent& event) {
requested_property,
&conversions)) {
std::vector<XAtom> conversion_results;
- for (size_t i = 0; i < conversions.size(); ++i) {
- bool conversion_successful = ProcessTarget(conversions[i].first,
- requestor,
- conversions[i].second);
- conversion_results.push_back(conversions[i].first);
- conversion_results.push_back(
- conversion_successful ? conversions[i].second : x11::None);
+ for (const std::pair<XAtom, XAtom>& conversion : conversions) {
+ bool conversion_successful =
+ ProcessTarget(conversion.first, requestor, conversion.second);
+ conversion_results.push_back(conversion.first);
+ conversion_results.push_back(conversion_successful ? conversion.second
+ : x11::None);
}
// Set the property to indicate which conversions succeeded. This matches
@@ -216,11 +214,8 @@ bool SelectionOwner::ProcessTarget(XAtom target,
if (target == targets_atom) {
// We have been asked for TARGETS. Send an atom array back with the data
// types we support.
- std::vector<XAtom> targets;
- targets.push_back(timestamp_atom);
- targets.push_back(targets_atom);
- targets.push_back(save_targets_atom);
- targets.push_back(multiple_atom);
+ std::vector<XAtom> targets = {timestamp_atom, targets_atom,
+ save_targets_atom, multiple_atom};
RetrieveTargets(&targets);
XChangeProperty(x_display_, requestor, property, XA_ATOM, 32,
@@ -302,7 +297,7 @@ void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) {
// transfer->data once the zero-sized chunk is sent to indicate that state
// related to this data transfer can be cleared.
if (chunk_length == 0)
- transfer->data = NULL;
+ transfer->data = nullptr;
}
void SelectionOwner::AbortStaleIncrementalTransfers() {
diff --git a/chromium/ui/base/x/selection_owner.h b/chromium/ui/base/x/selection_owner.h
index e1c5a95392e..0eef264c10e 100644
--- a/chromium/ui/base/x/selection_owner.h
+++ b/chromium/ui/base/x/selection_owner.h
@@ -22,9 +22,9 @@ namespace ui {
class XScopedEventSelector;
-extern const char kIncr[];
-extern const char kSaveTargets[];
-extern const char kTargets[];
+UI_BASE_EXPORT extern const char kIncr[];
+UI_BASE_EXPORT extern const char kSaveTargets[];
+UI_BASE_EXPORT extern const char kTargets[];
// Owns a specific X11 selection on an X window.
//
diff --git a/chromium/ui/base/x/selection_requestor.cc b/chromium/ui/base/x/selection_requestor.cc
index 8fb3bda7711..48a408022e2 100644
--- a/chromium/ui/base/x/selection_requestor.cc
+++ b/chromium/ui/base/x/selection_requestor.cc
@@ -38,16 +38,15 @@ scoped_refptr<base::RefCountedMemory> CombineRefCountedMemory(
if (data.size() == 1u)
return data[0];
- size_t length = 0;
- for (size_t i = 0; i < data.size(); ++i)
- length += data[i]->size();
+ size_t combined_length = 0;
+ for (const auto& datum : data)
+ combined_length += datum->size();
std::vector<unsigned char> combined_data;
- combined_data.reserve(length);
+ combined_data.reserve(combined_length);
- for (size_t i = 0; i < data.size(); ++i) {
- combined_data.insert(combined_data.end(),
- data[i]->front(),
- data[i]->front() + data[i]->size());
+ for (const auto& datum : data) {
+ combined_data.insert(combined_data.end(), datum->front(),
+ datum->front() + datum->size());
}
return base::RefCountedBytes::TakeVector(&combined_data);
}
@@ -109,21 +108,17 @@ void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
XAtom target,
const std::vector<XAtom>& parameter) {
SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter);
- PerformBlockingConvertSelection(selection, target, NULL, NULL, NULL);
+ PerformBlockingConvertSelection(selection, target, nullptr, nullptr, nullptr);
}
SelectionData SelectionRequestor::RequestAndWaitForTypes(
XAtom selection,
const std::vector<XAtom>& types) {
- for (auto it = types.begin(); it != types.end(); ++it) {
+ for (const XAtom& item : types) {
scoped_refptr<base::RefCountedMemory> data;
XAtom type = x11::None;
- if (PerformBlockingConvertSelection(selection,
- *it,
- &data,
- NULL,
- &type) &&
- type == *it) {
+ if (PerformBlockingConvertSelection(selection, item, &data, nullptr,
+ &type) && type == item) {
return SelectionData(type, data);
}
}
@@ -283,8 +278,9 @@ void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) {
}
SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() {
- return current_request_index_ == requests_.size() ?
- NULL : requests_[current_request_index_];
+ return current_request_index_ == requests_.size()
+ ? nullptr
+ : requests_[current_request_index_];
}
SelectionRequestor::Request::Request(XAtom selection,
diff --git a/chromium/ui/base/x/selection_requestor_unittest.cc b/chromium/ui/base/x/selection_requestor_unittest.cc
index 7cf997ec43d..3b8efd2fa9b 100644
--- a/chromium/ui/base/x/selection_requestor_unittest.cc
+++ b/chromium/ui/base/x/selection_requestor_unittest.cc
@@ -66,11 +66,11 @@ class SelectionRequestorTest : public testing::Test {
InputOnly,
CopyFromParent, // visual
0,
- NULL);
+ nullptr);
event_source_ = PlatformEventSource::CreateDefault();
CHECK(PlatformEventSource::GetInstance());
- requestor_.reset(new SelectionRequestor(x_display_, x_window_, NULL));
+ requestor_.reset(new SelectionRequestor(x_display_, x_window_, nullptr));
}
void TearDown() override {
diff --git a/chromium/ui/base/x/selection_utils.cc b/chromium/ui/base/x/selection_utils.cc
index c0947ea7821..b10721857bf 100644
--- a/chromium/ui/base/x/selection_utils.cc
+++ b/chromium/ui/base/x/selection_utils.cc
@@ -14,7 +14,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/gfx/x/x11_atom_cache.h"
namespace ui {
@@ -37,23 +37,23 @@ std::vector<::Atom> GetTextAtomsFrom() {
std::vector<::Atom> GetURLAtomsFrom() {
std::vector< ::Atom> atoms;
- atoms.push_back(gfx::GetAtom(Clipboard::kMimeTypeURIList));
- atoms.push_back(gfx::GetAtom(Clipboard::kMimeTypeMozillaURL));
+ atoms.push_back(gfx::GetAtom(kMimeTypeURIList));
+ atoms.push_back(gfx::GetAtom(kMimeTypeMozillaURL));
return atoms;
}
std::vector<::Atom> GetURIListAtomsFrom() {
std::vector< ::Atom> atoms;
- atoms.push_back(gfx::GetAtom(Clipboard::kMimeTypeURIList));
+ atoms.push_back(gfx::GetAtom(kMimeTypeURIList));
return atoms;
}
void GetAtomIntersection(const std::vector< ::Atom>& desired,
const std::vector< ::Atom>& offered,
std::vector< ::Atom>* output) {
- for (auto it = desired.begin(); it != desired.end(); ++it) {
- if (base::ContainsValue(offered, *it))
- output->push_back(*it);
+ for (const auto& desired_atom : desired) {
+ if (base::ContainsValue(offered, desired_atom))
+ output->push_back(desired_atom);
}
}
@@ -120,8 +120,8 @@ void SelectionFormatMap::Insert(
ui::SelectionData SelectionFormatMap::GetFirstOf(
const std::vector< ::Atom>& requested_types) const {
- for (auto it = requested_types.begin(); it != requested_types.end(); ++it) {
- auto data_it = data_.find(*it);
+ for (const auto& requested_type : requested_types) {
+ auto data_it = data_.find(requested_type);
if (data_it != data_.end()) {
return SelectionData(data_it->first, data_it->second);
}
@@ -132,8 +132,8 @@ ui::SelectionData SelectionFormatMap::GetFirstOf(
std::vector< ::Atom> SelectionFormatMap::GetTypes() const {
std::vector< ::Atom> atoms;
- for (auto it = data_.begin(); it != data_.end(); ++it)
- atoms.push_back(it->first);
+ for (const auto& datum : data_)
+ atoms.push_back(datum.first);
return atoms;
}
@@ -169,7 +169,7 @@ bool SelectionData::IsValid() const {
}
const unsigned char* SelectionData::GetData() const {
- return memory_.get() ? memory_->front() : NULL;
+ return memory_.get() ? memory_->front() : nullptr;
}
size_t SelectionData::GetSize() const {
@@ -198,7 +198,7 @@ std::string SelectionData::GetText() const {
base::string16 SelectionData::GetHtml() const {
base::string16 markup;
- if (type_ == gfx::GetAtom(Clipboard::kMimeTypeHTML)) {
+ if (type_ == gfx::GetAtom(kMimeTypeHTML)) {
const unsigned char* data = GetData();
size_t size = GetSize();
diff --git a/chromium/ui/base/x/selection_utils.h b/chromium/ui/base/x/selection_utils.h
index 2d2e99bb813..69542946439 100644
--- a/chromium/ui/base/x/selection_utils.h
+++ b/chromium/ui/base/x/selection_utils.h
@@ -9,16 +9,15 @@
#include <map>
#include "base/memory/ref_counted_memory.h"
-#include "ui/base/clipboard/clipboard.h"
#include "ui/base/ui_base_export.h"
#include "ui/gfx/x/x11.h"
namespace ui {
class SelectionData;
-extern const char kString[];
-extern const char kText[];
-extern const char kUtf8String[];
+UI_BASE_EXPORT extern const char kString[];
+UI_BASE_EXPORT extern const char kText[];
+UI_BASE_EXPORT extern const char kUtf8String[];
// Returns a list of all text atoms that we handle.
UI_BASE_EXPORT std::vector<::Atom> GetTextAtomsFrom();
diff --git a/chromium/ui/base/x/x11_display_util.cc b/chromium/ui/base/x/x11_display_util.cc
index c13067469e1..d2e8edab3d7 100644
--- a/chromium/ui/base/x/x11_display_util.cc
+++ b/chromium/ui/base/x/x11_display_util.cc
@@ -133,6 +133,10 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
output_info(XRRGetOutputInfo(xdisplay, resources.get(), output_id));
+ // XRRGetOutputInfo returns null in some cases: https://crbug.com/921490
+ if (!output_info)
+ continue;
+
bool is_connected = (output_info->connection == RR_Connected);
if (!is_connected)
continue;
diff --git a/chromium/ui/base/x/x11_util.cc b/chromium/ui/base/x/x11_util.cc
index 9d79f937bd1..3bcb6207755 100644
--- a/chromium/ui/base/x/x11_util.cc
+++ b/chromium/ui/base/x/x11_util.cc
@@ -22,7 +22,6 @@
#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/message_loop/message_loop_current.h"
#include "base/metrics/histogram_macros.h"
@@ -627,8 +626,7 @@ bool WindowContainsPoint(XID window, gfx::Point screen_loc) {
// included in both the default input region and the client bounding region
// will not be included in the effective input region on the screen.
int rectangle_kind[] = {ShapeInput, ShapeBounding};
- for (size_t kind_index = 0;
- kind_index < arraysize(rectangle_kind);
+ for (size_t kind_index = 0; kind_index < base::size(rectangle_kind);
kind_index++) {
int dummy;
int shape_rects_size = 0;
@@ -664,7 +662,7 @@ bool PropertyExists(XID window, const std::string& property_name) {
XAtom type = x11::None;
int format = 0; // size in bits of each item in 'property'
unsigned long num_items = 0;
- unsigned char* property = NULL;
+ unsigned char* property = nullptr;
int result = GetProperty(window, property_name, 1,
&type, &format, &num_items, &property);
@@ -685,7 +683,7 @@ bool GetRawBytesOfProperty(XID window,
unsigned long nbytes = 0;
XAtom prop_type = x11::None;
int prop_format = 0;
- unsigned char* property_data = NULL;
+ unsigned char* property_data = nullptr;
if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0, kLongLength,
x11::False, AnyPropertyType, &prop_type, &prop_format,
&nitems, &nbytes, &property_data) != x11::Success) {
@@ -698,7 +696,7 @@ bool GetRawBytesOfProperty(XID window,
size_t bytes = 0;
// So even though we should theoretically have nbytes (and we can't
- // pass NULL there), we need to manually calculate the byte length here
+ // pass nullptr there), we need to manually calculate the byte length here
// because nbytes always returns zero.
switch (prop_format) {
case 8:
@@ -731,7 +729,7 @@ bool GetIntProperty(XID window, const std::string& property_name, int* value) {
XAtom type = x11::None;
int format = 0; // size in bits of each item in 'property'
unsigned long num_items = 0;
- unsigned char* property = NULL;
+ unsigned char* property = nullptr;
int result = GetProperty(window, property_name, 1,
&type, &format, &num_items, &property);
@@ -750,7 +748,7 @@ bool GetXIDProperty(XID window, const std::string& property_name, XID* value) {
XAtom type = x11::None;
int format = 0; // size in bits of each item in 'property'
unsigned long num_items = 0;
- unsigned char* property = NULL;
+ unsigned char* property = nullptr;
int result = GetProperty(window, property_name, 1,
&type, &format, &num_items, &property);
@@ -771,7 +769,7 @@ bool GetIntArrayProperty(XID window,
XAtom type = x11::None;
int format = 0; // size in bits of each item in 'property'
unsigned long num_items = 0;
- unsigned char* properties = NULL;
+ unsigned char* properties = nullptr;
int result = GetProperty(window, property_name,
(~0L), // (all of them)
@@ -797,7 +795,7 @@ bool GetAtomArrayProperty(XID window,
XAtom type = x11::None;
int format = 0; // size in bits of each item in 'property'
unsigned long num_items = 0;
- unsigned char* properties = NULL;
+ unsigned char* properties = nullptr;
int result = GetProperty(window, property_name,
(~0L), // (all of them)
@@ -820,7 +818,7 @@ bool GetStringProperty(
XAtom type = x11::None;
int format = 0; // size in bits of each item in 'property'
unsigned long num_items = 0;
- unsigned char* property = NULL;
+ unsigned char* property = nullptr;
int result = GetProperty(window, property_name, 1024,
&type, &format, &num_items, &property);
@@ -1002,7 +1000,7 @@ bool GetWindowDesktop(XID window, int* desktop) {
std::string GetX11ErrorString(XDisplay* display, int err) {
char buffer[256];
- XGetErrorText(display, err, buffer, arraysize(buffer));
+ XGetErrorText(display, err, buffer, base::size(buffer));
return buffer;
}
@@ -1097,7 +1095,7 @@ bool GetXWindowStack(Window window, std::vector<XID>* windows) {
Atom type;
int format;
unsigned long count;
- unsigned char *data = NULL;
+ unsigned char* data = nullptr;
if (GetProperty(window, "_NET_CLIENT_LIST_STACKING", ~0L, &type, &format,
&count, &data) != x11::Success) {
return false;
@@ -1227,7 +1225,7 @@ bool IsCompositingManagerPresent() {
}
void SetDefaultX11ErrorHandlers() {
- SetX11ErrorHandlers(NULL, NULL);
+ SetX11ErrorHandlers(nullptr, nullptr);
}
bool IsX11WindowFullScreen(XID window) {
@@ -1348,7 +1346,7 @@ const XcursorImage* GetCachedXcursorImage(::Cursor cursor) {
// These functions are declared in x11_util_internal.h because they require
// XLib.h to be included, and it conflicts with many other headers.
XRenderPictFormat* GetRenderARGB32Format(XDisplay* dpy) {
- static XRenderPictFormat* pictformat = NULL;
+ static XRenderPictFormat* pictformat = nullptr;
if (pictformat)
return pictformat;
diff --git a/chromium/ui/chromeos/BUILD.gn b/chromium/ui/chromeos/BUILD.gn
index 7c4de18b330..d1075fcd6a8 100644
--- a/chromium/ui/chromeos/BUILD.gn
+++ b/chromium/ui/chromeos/BUILD.gn
@@ -29,8 +29,9 @@ component("chromeos") {
deps = [
"//base",
"//base/third_party/dynamic_annotations",
- "//chromeos:chromeos",
- "//chromeos:power_manager_proto",
+ "//chromeos",
+ "//chromeos/dbus",
+ "//chromeos/dbus:power_manager_proto",
"//components/device_event_log",
"//components/onc",
"//mojo/public/cpp/bindings",
@@ -69,6 +70,7 @@ test("ui_chromeos_unittests") {
":chromeos",
"//base/test:test_support",
"//chromeos",
+ "//chromeos:chromeos_buildflags",
"//mojo/core/embedder",
"//skia",
"//testing/gtest",
diff --git a/chromium/ui/compositor/BUILD.gn b/chromium/ui/compositor/BUILD.gn
index ab830a68656..4804d129daf 100644
--- a/chromium/ui/compositor/BUILD.gn
+++ b/chromium/ui/compositor/BUILD.gn
@@ -16,8 +16,6 @@ jumbo_component("compositor") {
"clip_recorder.h",
"closure_animation_observer.cc",
"closure_animation_observer.h",
- "compositing_recorder.cc",
- "compositing_recorder.h",
"compositor.cc",
"compositor.h",
"compositor_animation_observer.h",
diff --git a/chromium/ui/compositor/clip_recorder.cc b/chromium/ui/compositor/clip_recorder.cc
index 77acf0f7cfc..b5ab1435808 100644
--- a/chromium/ui/compositor/clip_recorder.cc
+++ b/chromium/ui/compositor/clip_recorder.cc
@@ -6,11 +6,11 @@
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_op_buffer.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/compositor/paint_context.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/skia_util.h"
namespace ui {
@@ -38,7 +38,7 @@ void ClipRecorder::ClipRect(const gfx::Rect& clip_rect) {
++num_closers_;
}
-void ClipRecorder::ClipPath(const gfx::Path& clip_path) {
+void ClipRecorder::ClipPath(const SkPath& clip_path) {
bool antialias = false;
context_.list_->StartPaint();
@@ -49,7 +49,7 @@ void ClipRecorder::ClipPath(const gfx::Path& clip_path) {
++num_closers_;
}
-void ClipRecorder::ClipPathWithAntiAliasing(const gfx::Path& clip_path) {
+void ClipRecorder::ClipPathWithAntiAliasing(const SkPath& clip_path) {
bool antialias = true;
context_.list_->StartPaint();
diff --git a/chromium/ui/compositor/clip_recorder.h b/chromium/ui/compositor/clip_recorder.h
index 7bc0eab96ed..f89ed9601be 100644
--- a/chromium/ui/compositor/clip_recorder.h
+++ b/chromium/ui/compositor/clip_recorder.h
@@ -9,14 +9,12 @@
#include "ui/compositor/compositor_export.h"
#include "ui/gfx/geometry/rect.h"
+class SkPath;
+
namespace cc {
class DisplayItemList;
}
-namespace gfx {
-class Path;
-}
-
namespace ui {
class PaintContext;
@@ -30,8 +28,8 @@ class COMPOSITOR_EXPORT ClipRecorder {
~ClipRecorder();
void ClipRect(const gfx::Rect& clip_rect);
- void ClipPath(const gfx::Path& clip_path);
- void ClipPathWithAntiAliasing(const gfx::Path& clip_path);
+ void ClipPath(const SkPath& clip_path);
+ void ClipPathWithAntiAliasing(const SkPath& clip_path);
private:
const PaintContext& context_;
diff --git a/chromium/ui/compositor/compositing_recorder.cc b/chromium/ui/compositor/compositing_recorder.cc
deleted file mode 100644
index ab4bf8826ab..00000000000
--- a/chromium/ui/compositor/compositing_recorder.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/compositor/compositing_recorder.h"
-
-#include "cc/paint/display_item_list.h"
-#include "cc/paint/paint_op_buffer.h"
-#include "ui/compositor/paint_context.h"
-#include "ui/gfx/canvas.h"
-
-namespace ui {
-
-CompositingRecorder::CompositingRecorder(const PaintContext& context,
- uint8_t alpha,
- bool lcd_text_requires_opaque_layer)
- : context_(context),
- saved_(alpha < 255) {
- if (!saved_)
- return;
-
- context_.list_->StartPaint();
- context_.list_->push<cc::SaveLayerAlphaOp>(nullptr, alpha,
- !lcd_text_requires_opaque_layer);
- context_.list_->EndPaintOfPairedBegin();
-}
-
-CompositingRecorder::~CompositingRecorder() {
- if (!saved_)
- return;
-
- context_.list_->StartPaint();
- context_.list_->push<cc::RestoreOp>();
- context_.list_->EndPaintOfPairedEnd();
-}
-
-} // namespace ui
diff --git a/chromium/ui/compositor/compositing_recorder.h b/chromium/ui/compositor/compositing_recorder.h
deleted file mode 100644
index 78817f9a01f..00000000000
--- a/chromium/ui/compositor/compositing_recorder.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_COMPOSITOR_COMPOSITING_RECORDER_H_
-#define UI_COMPOSITOR_COMPOSITING_RECORDER_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "ui/compositor/compositor_export.h"
-
-namespace ui {
-class PaintContext;
-
-// A class to provide scoped compositing filters (eg opacity) of painting to a
-// DisplayItemList. The filters provided will be applied to any
-// DisplayItems added to the DisplayItemList while this object is alive. In
-// other words, any nested PaintRecorders or other such Recorders will
-// be filtered by the effect.
-class COMPOSITOR_EXPORT CompositingRecorder {
- public:
- // |alpha| is a value between 0 and 255, where 0 is transparent and 255 is
- // opaque. |size_in_context| is the size in the |context|'s space surrounding
- // everything that's visible. |lcd_text_requires_opaque_layer| should
- // normally be true; if this is false, Skia will respect text rendering
- // requests for LCD AA even if they occur on non-opaque layers. This should
- // only be used in cases where the text is known to be rendered opaquely on an
- // opaque background before compositing.
- CompositingRecorder(const PaintContext& context,
- uint8_t alpha,
- bool lcd_text_requires_opaque_layer);
- ~CompositingRecorder();
-
- private:
- const PaintContext& context_;
- bool saved_;
-
- DISALLOW_COPY_AND_ASSIGN(CompositingRecorder);
-};
-
-} // namespace ui
-
-#endif // UI_COMPOSITOR_CLIP_TRANSFORM_RECORDER_H_
diff --git a/chromium/ui/compositor/compositor.cc b/chromium/ui/compositor/compositor.cc
index 5358941075a..74e8d5b78d5 100644
--- a/chromium/ui/compositor/compositor.cc
+++ b/chromium/ui/compositor/compositor.cc
@@ -63,21 +63,21 @@ const char* kDefaultTraceEnvironmentName = "browser";
} // namespace
-Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
- ui::ContextFactory* context_factory,
- ui::ContextFactoryPrivate* context_factory_private,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- bool enable_surface_synchronization,
- bool enable_pixel_canvas,
- bool external_begin_frames_enabled,
- bool force_software_compositor,
- const char* trace_environment_name)
+Compositor::Compositor(
+ const viz::FrameSinkId& frame_sink_id,
+ ui::ContextFactory* context_factory,
+ ui::ContextFactoryPrivate* context_factory_private,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ bool enable_pixel_canvas,
+ ui::ExternalBeginFrameClient* external_begin_frame_client,
+ 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),
task_runner_(task_runner),
vsync_manager_(new CompositorVSyncManager()),
- external_begin_frames_enabled_(external_begin_frames_enabled),
+ external_begin_frame_client_(external_begin_frame_client),
force_software_compositor_(force_software_compositor),
layer_animator_collection_(this),
is_pixel_canvas_(enable_pixel_canvas),
@@ -155,7 +155,7 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
settings.initial_debug_state.SetRecordRenderingStats(
command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
- settings.enable_surface_synchronization = enable_surface_synchronization;
+ settings.enable_surface_synchronization = true;
settings.build_hit_test_data = features::IsVizHitTestingSurfaceLayerEnabled();
settings.use_zero_copy = IsUIZeroCopyEnabled();
@@ -179,6 +179,20 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
#endif
settings.memory_policy.bytes_limit_when_visible = 512 * 1024 * 1024;
+
+ // Used to configure ui compositor memory limit for chromeos devices.
+ // See crbug.com/923141.
+ if (command_line->HasSwitch(
+ switches::kUiCompositorMemoryLimitWhenVisibleMB)) {
+ std::string value_str = command_line->GetSwitchValueASCII(
+ switches::kUiCompositorMemoryLimitWhenVisibleMB);
+ unsigned value_in_mb;
+ if (base::StringToUint(value_str, &value_in_mb)) {
+ settings.memory_policy.bytes_limit_when_visible =
+ 1024 * 1024 * value_in_mb;
+ }
+ }
+
settings.memory_policy.priority_cutoff_when_visible =
gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
@@ -190,9 +204,6 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
settings.enable_latency_recovery = false;
}
- settings.always_request_presentation_time =
- command_line->HasSwitch(cc::switches::kAlwaysRequestPresentationTime);
-
animation_host_ = cc::AnimationHost::CreateMainInstance();
cc::LayerTreeHost::InitParams params;
@@ -505,36 +516,6 @@ scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const {
return vsync_manager_;
}
-void Compositor::IssueExternalBeginFrame(const viz::BeginFrameArgs& args) {
- TRACE_EVENT1("ui", "Compositor::IssueExternalBeginFrame", "args",
- args.AsValue());
- DCHECK(external_begin_frames_enabled_);
- if (context_factory_private_)
- context_factory_private_->IssueExternalBeginFrame(this, args);
-}
-
-void Compositor::SetExternalBeginFrameClient(ExternalBeginFrameClient* client) {
- DCHECK(external_begin_frames_enabled_);
- external_begin_frame_client_ = client;
- if (needs_external_begin_frames_ && external_begin_frame_client_)
- external_begin_frame_client_->OnNeedsExternalBeginFrames(true);
-}
-
-void Compositor::OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) {
- DCHECK(external_begin_frames_enabled_);
- if (external_begin_frame_client_)
- external_begin_frame_client_->OnDisplayDidFinishFrame(ack);
-}
-
-void Compositor::OnNeedsExternalBeginFrames(bool needs_begin_frames) {
- DCHECK(external_begin_frames_enabled_);
- if (external_begin_frame_client_) {
- external_begin_frame_client_->OnNeedsExternalBeginFrames(
- needs_begin_frames);
- }
- needs_external_begin_frames_ = needs_begin_frames;
-}
-
void Compositor::AddObserver(CompositorObserver* observer) {
observer_list_.AddObserver(observer);
}
@@ -597,10 +578,10 @@ void Compositor::RequestNewLayerTreeFrameSink() {
}
void Compositor::DidFailToInitializeLayerTreeFrameSink() {
- // The LayerTreeFrameSink should already be bound/initialized before being
- // given to
- // the Compositor.
- NOTREACHED();
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&Compositor::RequestNewLayerTreeFrameSink,
+ context_creation_weak_ptr_factory_.GetWeakPtr()));
}
void Compositor::DidCommit() {
@@ -623,6 +604,12 @@ void Compositor::DidPresentCompositorFrame(
trace_environment_name_);
}
+void Compositor::DidGenerateLocalSurfaceIdAllocation(
+ const viz::LocalSurfaceIdAllocation& allocation) {
+ for (auto& observer : observer_list_)
+ observer.DidGenerateLocalSurfaceIdAllocation(this, allocation);
+}
+
void Compositor::DidSubmitCompositorFrame() {
base::TimeTicks start_time = base::TimeTicks::Now();
for (auto& observer : observer_list_)
diff --git a/chromium/ui/compositor/compositor.h b/chromium/ui/compositor/compositor.h
index 6f46fd5b4b5..313431f82ee 100644
--- a/chromium/ui/compositor/compositor.h
+++ b/chromium/ui/compositor/compositor.h
@@ -11,7 +11,6 @@
#include <string>
#include "base/callback_forward.h"
-#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
@@ -201,8 +200,7 @@ class COMPOSITOR_EXPORT ContextFactory {
// view hierarchy.
class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
public cc::LayerTreeHostSingleThreadClient,
- public viz::HostFrameSinkClient,
- public ExternalBeginFrameClient {
+ public viz::HostFrameSinkClient {
public:
// |trace_environment_name| is passed to trace events so that tracing
// can identify the environment the trace events are from. Examples are,
@@ -211,9 +209,8 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
ui::ContextFactory* context_factory,
ui::ContextFactoryPrivate* context_factory_private,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- bool enable_surface_synchronization,
bool enable_pixel_canvas,
- bool external_begin_frames_enabled = false,
+ ExternalBeginFrameClient* external_begin_frame_client = nullptr,
bool force_software_compositor = false,
const char* trace_environment_name = nullptr);
~Compositor() override;
@@ -323,16 +320,6 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
// Returns the vsync manager for this compositor.
scoped_refptr<CompositorVSyncManager> vsync_manager() const;
- bool external_begin_frames_enabled() {
- return external_begin_frames_enabled_;
- }
-
- void SetExternalBeginFrameClient(ExternalBeginFrameClient* client);
-
- // The ExternalBeginFrameClient calls this to issue a BeginFrame with the
- // given |args|.
- void IssueExternalBeginFrame(const viz::BeginFrameArgs& args);
-
// This flag is used to force a compositor into software compositing even tho
// in general chrome is using gpu compositing. This allows the compositor to
// be created without a gpu context, and does not go through the gpu path at
@@ -377,10 +364,6 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
base::OnceCallback<void(const gfx::PresentationFeedback&)>;
void RequestPresentationTimeForNextFrame(PresentationTimeCallback callback);
- // ExternalBeginFrameClient implementation.
- void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) override;
- void OnNeedsExternalBeginFrames(bool needs_begin_frames) override;
-
// LayerTreeHostClient implementation.
void WillBeginMainFrame() override {}
void DidBeginMainFrame() override {}
@@ -392,6 +375,11 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
}
void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel,
bool has_scrolled_by_touch) override {}
+ void SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) override {}
+ void SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) override {}
void RequestNewLayerTreeFrameSink() override;
void DidInitializeLayerTreeFrameSink() override {}
void DidFailToInitializeLayerTreeFrameSink() override;
@@ -404,6 +392,8 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
uint32_t frame_token,
const gfx::PresentationFeedback& feedback) override;
void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override {}
+ void DidGenerateLocalSurfaceIdAllocation(
+ const viz::LocalSurfaceIdAllocation& allocation) override;
// cc::LayerTreeHostSingleThreadClient implementation.
void DidSubmitCompositorFrame() override;
@@ -429,6 +419,10 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
int activated_frame_count() const { return activated_frame_count_; }
float refresh_rate() const { return refresh_rate_; }
+ ExternalBeginFrameClient* external_begin_frame_client() {
+ return external_begin_frame_client_;
+ }
+
void SetAllowLocksToExtendTimeout(bool allowed) {
lock_manager_.set_allow_locks_to_extend_timeout(allowed);
}
@@ -480,9 +474,7 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
base::TimeTicks vsync_timebase_;
base::TimeDelta vsync_interval_;
- bool external_begin_frames_enabled_;
- ExternalBeginFrameClient* external_begin_frame_client_ = nullptr;
- bool needs_external_begin_frames_ = false;
+ ExternalBeginFrameClient* const external_begin_frame_client_;
const bool force_software_compositor_;
diff --git a/chromium/ui/compositor/compositor_observer.h b/chromium/ui/compositor/compositor_observer.h
index 4225c8acd6c..5745c3cba89 100644
--- a/chromium/ui/compositor/compositor_observer.h
+++ b/chromium/ui/compositor/compositor_observer.h
@@ -8,6 +8,10 @@
#include "base/time/time.h"
#include "ui/compositor/compositor_export.h"
+namespace viz {
+class LocalSurfaceIdAllocation;
+}
+
namespace ui {
class Compositor;
@@ -24,22 +28,30 @@ class COMPOSITOR_EXPORT CompositorObserver {
// between two composites (just before the composite as part of the
// composite cycle). If the compositor is locked, it will not send this
// this signal.
- virtual void OnCompositingDidCommit(Compositor* compositor) = 0;
+ virtual void OnCompositingDidCommit(Compositor* compositor) {}
// Called when compositing started: it has taken all the layer changes into
// account and has issued the graphics commands.
virtual void OnCompositingStarted(Compositor* compositor,
- base::TimeTicks start_time) = 0;
+ base::TimeTicks start_time) {}
// Called when compositing completes: the present to screen has completed.
- virtual void OnCompositingEnded(Compositor* compositor) = 0;
+ virtual void OnCompositingEnded(Compositor* compositor) {}
// Called when a child of the compositor is resizing.
- virtual void OnCompositingChildResizing(Compositor* compositor) = 0;
+ virtual void OnCompositingChildResizing(Compositor* compositor) {}
// Called at the top of the compositor's destructor, to give observers a
// chance to remove themselves.
- virtual void OnCompositingShuttingDown(Compositor* compositor) = 0;
+ virtual void OnCompositingShuttingDown(Compositor* compositor) {}
+
+ // Called (asynchronously) when the compositor generates a new
+ // LocalSurfaceIdAllocation. For example, if
+ // LayerTreeHost::RequestNewLocalSurfaceId() is called, then this function
+ // is called once the compositor generates the new LocalSurfaceIdAllocation.
+ virtual void DidGenerateLocalSurfaceIdAllocation(
+ Compositor* compositor,
+ const viz::LocalSurfaceIdAllocation& allocation) {}
};
} // namespace ui
diff --git a/chromium/ui/compositor/compositor_switches.cc b/chromium/ui/compositor/compositor_switches.cc
index a61a7ba9b59..842a3dce204 100644
--- a/chromium/ui/compositor/compositor_switches.cc
+++ b/chromium/ui/compositor/compositor_switches.cc
@@ -29,6 +29,9 @@ const char kUISlowAnimations[] = "ui-slow-animations";
const char kDisableVsyncForTests[] = "disable-vsync-for-tests";
+const char kUiCompositorMemoryLimitWhenVisibleMB[] =
+ "ui-compositor-memory-limit-when-visible-mb";
+
} // namespace switches
namespace features {
diff --git a/chromium/ui/compositor/compositor_switches.h b/chromium/ui/compositor/compositor_switches.h
index 8757e22e970..d1abbfe30f4 100644
--- a/chromium/ui/compositor/compositor_switches.h
+++ b/chromium/ui/compositor/compositor_switches.h
@@ -18,6 +18,7 @@ COMPOSITOR_EXPORT extern const char kUIDisableZeroCopy[];
COMPOSITOR_EXPORT extern const char kUIShowPaintRects[];
COMPOSITOR_EXPORT extern const char kUISlowAnimations[];
COMPOSITOR_EXPORT extern const char kDisableVsyncForTests[];
+COMPOSITOR_EXPORT extern const char kUiCompositorMemoryLimitWhenVisibleMB[];
} // namespace switches
diff --git a/chromium/ui/compositor/compositor_unittest.cc b/chromium/ui/compositor/compositor_unittest.cc
index d393b18fdff..79dda58b2ad 100644
--- a/chromium/ui/compositor/compositor_unittest.cc
+++ b/chromium/ui/compositor/compositor_unittest.cc
@@ -43,7 +43,6 @@ class CompositorTest : public testing::Test {
compositor_.reset(new ui::Compositor(
context_factory_private->AllocateFrameSinkId(), context_factory,
context_factory_private, CreateTaskRunner(),
- false /* enable_surface_synchronization */,
false /* enable_pixel_canvas */));
compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
}
@@ -105,10 +104,12 @@ class CompositorTestWithMessageLoop : public CompositorTest {
TEST_F(CompositorTestWithMessageLoop, OutputColorMatrix) {
auto root_layer = std::make_unique<Layer>(ui::LAYER_SOLID_COLOR);
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
root_layer->SetBounds(gfx::Rect(10, 10));
compositor()->SetRootLayer(root_layer.get());
compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10),
- viz::LocalSurfaceIdAllocation());
+ allocator.GetCurrentLocalSurfaceIdAllocation());
DCHECK(compositor()->IsVisible());
// Set a non-identity color matrix on the compistor display, and expect it to
@@ -159,10 +160,12 @@ TEST_F(CompositorTestWithMockedTime,
#endif
TEST_F(CompositorTestWithMessageLoop, MAYBE_CreateAndReleaseOutputSurface) {
std::unique_ptr<Layer> root_layer(new Layer(ui::LAYER_SOLID_COLOR));
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
root_layer->SetBounds(gfx::Rect(10, 10));
compositor()->SetRootLayer(root_layer.get());
compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10),
- viz::LocalSurfaceIdAllocation());
+ allocator.GetCurrentLocalSurfaceIdAllocation());
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 e16c5490bbc..8297e1aabe3 100644
--- a/chromium/ui/compositor/host/host_context_factory_private.cc
+++ b/chromium/ui/compositor/host/host_context_factory_private.cc
@@ -78,9 +78,10 @@ void HostContextFactoryPrivate::ConfigureCompositor(
// Initialize ExternalBeginFrameController client if enabled.
compositor_data.external_begin_frame_controller_client.reset();
- if (compositor->external_begin_frames_enabled()) {
+ if (compositor->external_begin_frame_client()) {
compositor_data.external_begin_frame_controller_client =
- std::make_unique<ExternalBeginFrameControllerClientImpl>(compositor);
+ std::make_unique<ExternalBeginFrameControllerClientImpl>(
+ compositor->external_begin_frame_client());
root_params->external_begin_frame_controller =
compositor_data.external_begin_frame_controller_client
->GetControllerRequest();
@@ -116,8 +117,6 @@ void HostContextFactoryPrivate::ConfigureCompositor(
compositor->context_factory()->GetGpuMemoryBufferManager();
params.pipes.compositor_frame_sink_associated_info = std::move(sink_info);
params.pipes.client_request = std::move(client_request);
- params.local_surface_id_provider =
- std::make_unique<viz::DefaultLocalSurfaceIdProvider>();
params.enable_surface_synchronization = true;
if (features::IsVizHitTestingDrawQuadEnabled()) {
params.hit_test_data_provider =
@@ -141,6 +140,14 @@ void HostContextFactoryPrivate::UnconfigureCompositor(Compositor* compositor) {
compositor_data_map_.erase(compositor);
}
+base::flat_set<Compositor*> HostContextFactoryPrivate::GetAllCompositors() {
+ base::flat_set<Compositor*> all_compositors;
+ all_compositors.reserve(compositor_data_map_.size());
+ for (auto& pair : compositor_data_map_)
+ all_compositors.insert(pair.first);
+ return all_compositors;
+}
+
std::unique_ptr<Reflector> HostContextFactoryPrivate::CreateReflector(
Compositor* source,
Layer* target) {
@@ -258,14 +265,6 @@ viz::FrameSinkManagerImpl* HostContextFactoryPrivate::GetFrameSinkManager() {
return nullptr;
}
-base::flat_set<Compositor*> HostContextFactoryPrivate::GetAllCompositors() {
- base::flat_set<Compositor*> all_compositors;
- all_compositors.reserve(compositor_data_map_.size());
- for (auto& pair : compositor_data_map_)
- all_compositors.insert(pair.first);
- return all_compositors;
-}
-
HostContextFactoryPrivate::CompositorData::CompositorData() = default;
HostContextFactoryPrivate::CompositorData::CompositorData(
CompositorData&& other) = default;
diff --git a/chromium/ui/compositor/host/host_context_factory_private.h b/chromium/ui/compositor/host/host_context_factory_private.h
index 69a441e9fbc..a74630258fd 100644
--- a/chromium/ui/compositor/host/host_context_factory_private.h
+++ b/chromium/ui/compositor/host/host_context_factory_private.h
@@ -50,6 +50,19 @@ class HostContextFactoryPrivate : public ContextFactoryPrivate {
void UnconfigureCompositor(Compositor* compositor);
+ void set_is_gpu_compositing_disabled(bool value) {
+ is_gpu_compositing_disabled_ = value;
+ }
+ bool is_gpu_compositing_disabled() const {
+ return is_gpu_compositing_disabled_;
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> resize_task_runner() {
+ return resize_task_runner_;
+ }
+
+ base::flat_set<Compositor*> GetAllCompositors();
+
// ContextFactoryPrivate implementation.
std::unique_ptr<Reflector> CreateReflector(Compositor* source,
Layer* target) override;
@@ -72,20 +85,6 @@ class HostContextFactoryPrivate : public ContextFactoryPrivate {
void SetOutputIsSecure(Compositor* compositor, bool secure) override;
viz::FrameSinkManagerImpl* GetFrameSinkManager() override;
- protected:
- void set_is_gpu_compositing_disabled(bool value) {
- is_gpu_compositing_disabled_ = value;
- }
- bool is_gpu_compositing_disabled() const {
- return is_gpu_compositing_disabled_;
- }
-
- scoped_refptr<base::SingleThreadTaskRunner> resize_task_runner() {
- return resize_task_runner_;
- }
-
- base::flat_set<Compositor*> GetAllCompositors();
-
private:
struct CompositorData {
CompositorData();
diff --git a/chromium/ui/compositor/layer.cc b/chromium/ui/compositor/layer.cc
index b605b586cdd..a1fcf036bd1 100644
--- a/chromium/ui/compositor/layer.cc
+++ b/chromium/ui/compositor/layer.cc
@@ -166,6 +166,9 @@ Layer::~Layer() {
for (auto* child : children_)
child->parent_ = nullptr;
+ if (content_layer_)
+ content_layer_->ClearClient();
+ cc_layer_->SetLayerClient(nullptr);
cc_layer_->RemoveFromParent();
if (transfer_release_callback_)
transfer_release_callback_->Run(gpu::SyncToken(), false);
@@ -219,6 +222,17 @@ std::unique_ptr<Layer> Layer::Clone() const {
std::unique_ptr<Layer> Layer::Mirror() {
auto mirror = Clone();
mirrors_.emplace_back(std::make_unique<LayerMirror>(this, mirror.get()));
+
+ if (!transfer_resource_.mailbox_holder.mailbox.IsZero()) {
+ // Send an empty release callback because we don't want the resource to be
+ // freed up until the original layer releases it.
+ mirror->SetTransferableResource(
+ transfer_resource_,
+ viz::SingleReleaseCallback::Create(base::BindOnce(
+ [](const gpu::SyncToken& sync_token, bool is_lost) {})),
+ frame_size_in_dip_);
+ }
+
return mirror;
}
@@ -524,7 +538,6 @@ void Layer::SetLayerBackgroundFilters() {
filters.Append(cc::FilterOperation::CreateBlurFilter(
background_blur_sigma_, SkBlurImageFilter::kClamp_TileMode));
}
-
cc_layer_->SetBackdropFilters(filters);
}
@@ -626,7 +639,10 @@ void Layer::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) {
new_layer->SetTrilinearFiltering(cc_layer_->trilinear_filtering());
cc_layer_ = new_layer.get();
- content_layer_ = nullptr;
+ if (content_layer_) {
+ content_layer_->ClearClient();
+ content_layer_ = nullptr;
+ }
solid_color_layer_ = nullptr;
texture_layer_ = nullptr;
surface_layer_ = nullptr;
@@ -755,6 +771,16 @@ void Layer::SetTransferableResource(
transfer_release_callback_ = std::move(release_callback);
transfer_resource_ = resource;
SetTextureSize(texture_size_in_dip);
+
+ for (const auto& mirror : mirrors_) {
+ // The release callbacks should be empty as only the source layer
+ // should be able to release the texture resource.
+ mirror->dest()->SetTransferableResource(
+ transfer_resource_,
+ viz::SingleReleaseCallback::Create(base::BindOnce(
+ [](const gpu::SyncToken& sync_token, bool is_lost) {})),
+ frame_size_in_dip_);
+ }
}
void Layer::SetTextureSize(gfx::Size texture_size_in_dip) {
@@ -859,6 +885,9 @@ void Layer::SetShowSolidColorContent() {
transfer_release_callback_.reset();
}
RecomputeDrawsContentAndUVRect();
+
+ for (const auto& mirror : mirrors_)
+ mirror->dest()->SetShowSolidColorContent();
}
void Layer::UpdateNinePatchLayerImage(const gfx::ImageSkia& image) {
@@ -1181,6 +1210,10 @@ void Layer::SetOpacityFromAnimation(float opacity,
void Layer::SetVisibilityFromAnimation(bool visible,
PropertyChangeReason reason) {
+ // Sync changes with the mirror layers.
+ for (const auto& mirror : mirrors_)
+ mirror->dest()->SetVisible(visible);
+
if (visible_ == visible)
return;
diff --git a/chromium/ui/compositor/layer.h b/chromium/ui/compositor/layer.h
index 3e1771ffb45..e90777f3935 100644
--- a/chromium/ui/compositor/layer.h
+++ b/chromium/ui/compositor/layer.h
@@ -249,8 +249,10 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
void SetMaskLayer(Layer* layer_mask);
Layer* layer_mask_layer() { return layer_mask_; }
- // Sets the visibility of the Layer. A Layer may be visible but not
- // drawn. This happens if any ancestor of a Layer is not visible.
+ // Sets the visibility of the Layer. A Layer may be visible but not drawn.
+ // This happens if any ancestor of a Layer is not visible.
+ // Any changes made to this in the source layer will override the visibility
+ // of its mirror layer.
void SetVisible(bool visible);
bool visible() const { return visible_; }
diff --git a/chromium/ui/compositor/layer_animator.cc b/chromium/ui/compositor/layer_animator.cc
index 3c3efd6959c..b5c5886e9a7 100644
--- a/chromium/ui/compositor/layer_animator.cc
+++ b/chromium/ui/compositor/layer_animator.cc
@@ -227,7 +227,8 @@ void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) {
scoped_refptr<LayerAnimator> retain(this);
OnScheduled(animation);
if (is_animating()) {
- animation_queue_.push_back(make_linked_ptr(animation));
+ animation_queue_.push_back(
+ std::unique_ptr<LayerAnimationSequence>(animation));
ProcessQueue();
} else {
StartSequenceImmediately(animation);
@@ -536,7 +537,7 @@ void LayerAnimator::UpdateAnimationState() {
LayerAnimationSequence* LayerAnimator::RemoveAnimation(
LayerAnimationSequence* sequence) {
- linked_ptr<LayerAnimationSequence> to_return;
+ std::unique_ptr<LayerAnimationSequence> to_return;
bool is_running = false;
@@ -553,8 +554,8 @@ LayerAnimationSequence* LayerAnimator::RemoveAnimation(
// Then remove from the queue
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
- if ((*queue_iter) == sequence) {
- to_return = *queue_iter;
+ if (queue_iter->get() == sequence) {
+ to_return = std::move(*queue_iter);
animation_queue_.erase(queue_iter);
break;
}
@@ -651,14 +652,16 @@ void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) {
bool found_sequence = false;
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
- if ((*queue_iter) == animation) {
+ if (queue_iter->get() == animation) {
found_sequence = true;
break;
}
}
- if (!found_sequence)
- animation_queue_.push_front(make_linked_ptr(animation));
+ if (!found_sequence) {
+ animation_queue_.push_front(
+ std::unique_ptr<LayerAnimationSequence>(animation));
+ }
}
void LayerAnimator::RemoveAllAnimationsWithACommonProperty(
@@ -749,7 +752,7 @@ void LayerAnimator::EnqueueNewAnimation(LayerAnimationSequence* sequence) {
// It is assumed that if there was no conflicting animation, we would
// not have been called. No need to check for a collision; just
// add to the queue.
- animation_queue_.push_back(make_linked_ptr(sequence));
+ animation_queue_.push_back(std::unique_ptr<LayerAnimationSequence>(sequence));
ProcessQueue();
}
@@ -782,7 +785,7 @@ void LayerAnimator::ReplaceQueuedAnimations(LayerAnimationSequence* sequence) {
else
++i;
}
- animation_queue_.push_back(make_linked_ptr(sequence));
+ animation_queue_.push_back(std::unique_ptr<LayerAnimationSequence>(sequence));
ProcessQueue();
}
diff --git a/chromium/ui/compositor/layer_animator.h b/chromium/ui/compositor/layer_animator.h
index 4e3145d401b..842f111e96a 100644
--- a/chromium/ui/compositor/layer_animator.h
+++ b/chromium/ui/compositor/layer_animator.h
@@ -11,7 +11,6 @@
#include "base/containers/circular_deque.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/time/time.h"
@@ -273,7 +272,7 @@ class COMPOSITOR_EXPORT LayerAnimator : public base::RefCounted<LayerAnimator>,
using RunningAnimations = std::vector<RunningAnimation>;
using AnimationQueue =
- base::circular_deque<linked_ptr<LayerAnimationSequence>>;
+ base::circular_deque<std::unique_ptr<LayerAnimationSequence>>;
// Finishes all animations by either advancing them to their final state or by
// aborting them.
diff --git a/chromium/ui/compositor/layer_owner_unittest.cc b/chromium/ui/compositor/layer_owner_unittest.cc
index 2e6fb209019..1a57e9beb4c 100644
--- a/chromium/ui/compositor/layer_owner_unittest.cc
+++ b/chromium/ui/compositor/layer_owner_unittest.cc
@@ -85,7 +85,6 @@ void LayerOwnerTestWithCompositor::SetUp() {
compositor_.reset(
new ui::Compositor(context_factory_private->AllocateFrameSinkId(),
context_factory, context_factory_private, task_runner,
- false /* enable_surface_synchronization */,
false /* enable_pixel_canvas */));
compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
}
diff --git a/chromium/ui/compositor/layer_unittest.cc b/chromium/ui/compositor/layer_unittest.cc
index efad60457e3..5314e488e27 100644
--- a/chromium/ui/compositor/layer_unittest.cc
+++ b/chromium/ui/compositor/layer_unittest.cc
@@ -413,10 +413,6 @@ class TestCompositorObserver : public CompositorObserver {
void OnCompositingEnded(Compositor* compositor) override { ended_ = true; }
- void OnCompositingChildResizing(Compositor* compositor) override {}
-
- void OnCompositingShuttingDown(Compositor* compositor) override {}
-
bool committed_ = false;
bool started_ = false;
bool ended_ = false;
@@ -1121,6 +1117,110 @@ TEST_F(LayerWithNullDelegateTest, Visibility) {
EXPECT_TRUE(l3->cc_layer_for_testing()->hide_layer_and_subtree());
}
+// Various visible/drawn assertions.
+TEST_F(LayerWithNullDelegateTest, MirroringVisibility) {
+ std::unique_ptr<Layer> l1(new Layer(LAYER_TEXTURED));
+ std::unique_ptr<Layer> l2(new Layer(LAYER_TEXTURED));
+ std::unique_ptr<Layer> l2_mirror = l2->Mirror();
+ l1->Add(l2.get());
+ l1->Add(l2_mirror.get());
+
+ NullLayerDelegate delegate;
+ l1->set_delegate(&delegate);
+ l2->set_delegate(&delegate);
+ l2_mirror->set_delegate(&delegate);
+
+ // Layers should initially be drawn.
+ EXPECT_TRUE(l1->IsDrawn());
+ EXPECT_TRUE(l2->IsDrawn());
+ EXPECT_TRUE(l2_mirror->IsDrawn());
+ EXPECT_FALSE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2_mirror->cc_layer_for_testing()->hide_layer_and_subtree());
+
+ compositor()->SetRootLayer(l1.get());
+
+ Draw();
+
+ // Hiding the root layer should hide that specific layer and its subtree.
+ l1->SetVisible(false);
+
+ // Since the entire subtree is hidden, no layer should be drawn.
+ EXPECT_FALSE(l1->IsDrawn());
+ EXPECT_FALSE(l2->IsDrawn());
+ EXPECT_FALSE(l2_mirror->IsDrawn());
+
+ // The visibitily property for the subtree is rooted at |l1|.
+ EXPECT_TRUE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2_mirror->cc_layer_for_testing()->hide_layer_and_subtree());
+
+ // Hiding |l2| should also set the visibility on its mirror layer. In this
+ // case the visibility of |l2| will be mirrored by |l2_mirror|.
+ l2->SetVisible(false);
+
+ // None of the layers are drawn since the visibility is false at every node.
+ EXPECT_FALSE(l1->IsDrawn());
+ EXPECT_FALSE(l2->IsDrawn());
+ EXPECT_FALSE(l2_mirror->IsDrawn());
+
+ // Visibility property is set on every node and hence their subtree is also
+ // hidden.
+ EXPECT_TRUE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_TRUE(l2->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_TRUE(l2_mirror->cc_layer_for_testing()->hide_layer_and_subtree());
+
+ // Setting visibility on the root layer should make that layer visible and its
+ // subtree ready for visibility.
+ l1->SetVisible(true);
+ EXPECT_TRUE(l1->IsDrawn());
+ EXPECT_FALSE(l2->IsDrawn());
+ EXPECT_FALSE(l2_mirror->IsDrawn());
+ EXPECT_FALSE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_TRUE(l2->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_TRUE(l2_mirror->cc_layer_for_testing()->hide_layer_and_subtree());
+
+ // Setting visibility on the mirrored layer should not effect its source
+ // layer.
+ l2_mirror->SetVisible(true);
+ EXPECT_TRUE(l1->IsDrawn());
+ EXPECT_FALSE(l2->IsDrawn());
+ EXPECT_TRUE(l2_mirror->IsDrawn());
+ EXPECT_FALSE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_TRUE(l2->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2_mirror->cc_layer_for_testing()->hide_layer_and_subtree());
+
+ // Setting visibility on the source layer should keep the mirror layer in
+ // sync and not cause any invalid state.
+ l2->SetVisible(true);
+ EXPECT_TRUE(l1->IsDrawn());
+ EXPECT_TRUE(l2->IsDrawn());
+ EXPECT_TRUE(l2_mirror->IsDrawn());
+ EXPECT_FALSE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2_mirror->cc_layer_for_testing()->hide_layer_and_subtree());
+
+ // Setting visibility on the mirrored layer should not effect its source
+ // layer.
+ l2_mirror->SetVisible(false);
+ EXPECT_TRUE(l1->IsDrawn());
+ EXPECT_TRUE(l2->IsDrawn());
+ EXPECT_FALSE(l2_mirror->IsDrawn());
+ EXPECT_FALSE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_TRUE(l2_mirror->cc_layer_for_testing()->hide_layer_and_subtree());
+
+ // Setting source layer's visibility to true should update the mirror layer
+ // even if the source layer did not change in the process.
+ l2->SetVisible(true);
+ EXPECT_TRUE(l1->IsDrawn());
+ EXPECT_TRUE(l2->IsDrawn());
+ EXPECT_TRUE(l2_mirror->IsDrawn());
+ EXPECT_FALSE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2->cc_layer_for_testing()->hide_layer_and_subtree());
+ EXPECT_FALSE(l2_mirror->cc_layer_for_testing()->hide_layer_and_subtree());
+}
+
// Checks that stacking-related methods behave as advertised.
TEST_F(LayerWithNullDelegateTest, Stacking) {
std::unique_ptr<Layer> root(new Layer(LAYER_NOT_DRAWN));
@@ -1512,8 +1612,10 @@ 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::LocalSurfaceIdAllocation());
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(50, 50), allocator.GetCurrentLocalSurfaceIdAllocation());
// l0
// +-l11
@@ -1577,14 +1679,104 @@ TEST_F(LayerWithRealCompositorTest, ModifyHierarchy) {
EXPECT_TRUE(MatchesPNGFile(bitmap, ref_img2, cc::ExactPixelComparator(true)));
}
+// Checks that basic background blur is working.
+TEST_F(LayerWithRealCompositorTest, BackgroundBlur) {
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(200, 200),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
+ // l0
+ // +-l1
+ // +-l2
+ std::unique_ptr<Layer> l0(
+ CreateColorLayer(SK_ColorRED, gfx::Rect(0, 0, 200, 200)));
+ std::unique_ptr<Layer> l1(
+ CreateColorLayer(SK_ColorGREEN, gfx::Rect(100, 100, 100, 100)));
+ SkColor blue_with_alpha = SkColorSetARGB(40, 10, 20, 200);
+ std::unique_ptr<Layer> l2(
+ CreateColorLayer(blue_with_alpha, gfx::Rect(50, 50, 100, 100)));
+ l2->SetFillsBoundsOpaquely(false);
+ l2->SetBackgroundBlur(15);
+
+ base::FilePath ref_img1 = test_data_dir().AppendASCII("BackgroundBlur1.png");
+ base::FilePath ref_img2 = test_data_dir().AppendASCII("BackgroundBlur2.png");
+ SkBitmap bitmap;
+
+ l0->Add(l1.get());
+ l0->Add(l2.get());
+ DrawTree(l0.get());
+ ReadPixels(&bitmap);
+ ASSERT_FALSE(bitmap.empty());
+ // WritePNGFile(bitmap, ref_img1, false);
+ EXPECT_TRUE(MatchesPNGFile(bitmap, ref_img1, cc::ExactPixelComparator(true)));
+
+ l0->StackAtTop(l1.get());
+ DrawTree(l0.get());
+ ReadPixels(&bitmap);
+ ASSERT_FALSE(bitmap.empty());
+ // WritePNGFile(bitmap, ref_img2, false);
+ EXPECT_TRUE(MatchesPNGFile(bitmap, ref_img2, cc::ExactPixelComparator(true)));
+}
+
+// Checks that background blur bounds rect gets properly updated when device
+// scale changes.
+TEST_F(LayerWithRealCompositorTest, BackgroundBlurChangeDeviceScale) {
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(200, 200),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
+ // l0
+ // +-l1
+ // +-l2
+ std::unique_ptr<Layer> l0(
+ CreateColorLayer(SK_ColorRED, gfx::Rect(0, 0, 200, 200)));
+ std::unique_ptr<Layer> l1(
+ CreateColorLayer(SK_ColorGREEN, gfx::Rect(100, 100, 100, 100)));
+ SkColor blue_with_alpha = SkColorSetARGB(40, 10, 20, 200);
+ std::unique_ptr<Layer> l2(
+ CreateColorLayer(blue_with_alpha, gfx::Rect(50, 50, 100, 100)));
+ l2->SetFillsBoundsOpaquely(false);
+ l2->SetBackgroundBlur(15);
+
+ base::FilePath ref_img1 = test_data_dir().AppendASCII("BackgroundBlur1.png");
+ base::FilePath ref_img2 =
+ test_data_dir().AppendASCII("BackgroundBlur1_zoom.png");
+ SkBitmap bitmap;
+
+ l0->Add(l1.get());
+ l0->Add(l2.get());
+ DrawTree(l0.get());
+ ReadPixels(&bitmap);
+ ASSERT_FALSE(bitmap.empty());
+ // See LayerWithRealCompositorTest.BackgroundBlur test to rewrite this
+ // baseline.
+ EXPECT_TRUE(MatchesPNGFile(bitmap, ref_img1, cc::ExactPixelComparator(true)));
+
+ allocator.GenerateId();
+ // Now change the scale, and make sure the bounds are still correct.
+ GetCompositor()->SetScaleAndSize(
+ 2.0f, gfx::Size(200, 200),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
+ DrawTree(l0.get());
+ ReadPixels(&bitmap);
+ ASSERT_FALSE(bitmap.empty());
+ // WritePNGFile(bitmap, ref_img2, false);
+ EXPECT_TRUE(MatchesPNGFile(bitmap, ref_img2, cc::ExactPixelComparator(true)));
+}
+
// It is really hard to write pixel test on text rendering,
// due to different font appearance.
// So we choose to check result only on Windows.
// See https://codereview.chromium.org/1634103003/#msg41
#if defined(OS_WIN)
TEST_F(LayerWithRealCompositorTest, CanvasDrawFadedString) {
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
gfx::Size size(50, 50);
- GetCompositor()->SetScaleAndSize(1.0f, size, viz::LocalSurfaceIdAllocation());
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
DrawFadedStringLayerDelegate delegate(SK_ColorBLUE, size);
std::unique_ptr<Layer> layer(
CreateDrawFadedStringLayerDelegate(gfx::Rect(size), &delegate));
@@ -1617,8 +1809,10 @@ TEST_F(LayerWithRealCompositorTest, CanvasDrawFadedString) {
// Opacity is rendered correctly.
// Checks that modifying the hierarchy correctly affects final composite.
TEST_F(LayerWithRealCompositorTest, Opacity) {
- GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(50, 50),
- viz::LocalSurfaceIdAllocation());
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(50, 50), allocator.GetCurrentLocalSurfaceIdAllocation());
// l0
// +-l11
@@ -1734,8 +1928,11 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
l1->set_delegate(&l1_delegate);
l1_delegate.set_layer_bounds(l1->bounds());
- GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(500, 500),
- viz::LocalSurfaceIdAllocation());
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(500, 500),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
GetCompositor()->SetRootLayer(root.get());
root->Add(l1.get());
WaitForDraw();
@@ -1751,8 +1948,10 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
EXPECT_EQ(0.0f, l1_delegate.device_scale_factor());
// Scale up to 2.0. Changing scale doesn't change the bounds in DIP.
- GetCompositor()->SetScaleAndSize(2.0f, gfx::Size(500, 500),
- viz::LocalSurfaceIdAllocation());
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 2.0f, gfx::Size(500, 500),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
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.
@@ -1766,8 +1965,10 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
EXPECT_EQ(2.0f, l1_delegate.device_scale_factor());
// Scale down back to 1.0f.
- GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(500, 500),
- viz::LocalSurfaceIdAllocation());
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(500, 500),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
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.
@@ -1784,14 +1985,18 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
l1_delegate.reset();
// Just changing the size shouldn't notify the scale change nor
// trigger repaint.
- GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(1000, 1000),
- viz::LocalSurfaceIdAllocation());
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(1000, 1000),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
// 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());
}
TEST_F(LayerWithRealCompositorTest, ScaleReparent) {
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
std::unique_ptr<Layer> root(
CreateColorLayer(SK_ColorWHITE, gfx::Rect(10, 20, 200, 220)));
std::unique_ptr<Layer> l1(
@@ -1801,8 +2006,9 @@ TEST_F(LayerWithRealCompositorTest, ScaleReparent) {
l1->set_delegate(&l1_delegate);
l1_delegate.set_layer_bounds(l1->bounds());
- GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(500, 500),
- viz::LocalSurfaceIdAllocation());
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(500, 500),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
GetCompositor()->SetRootLayer(root.get());
root->Add(l1.get());
@@ -1815,8 +2021,10 @@ TEST_F(LayerWithRealCompositorTest, ScaleReparent) {
root->Remove(l1.get());
EXPECT_EQ(NULL, l1->parent());
EXPECT_EQ(NULL, l1->GetCompositor());
- GetCompositor()->SetScaleAndSize(2.0f, gfx::Size(500, 500),
- viz::LocalSurfaceIdAllocation());
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 2.0f, gfx::Size(500, 500),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
// Sanity check on root and l1.
EXPECT_EQ("10,20 200x220", root->bounds().ToString());
cc_bounds_size = l1->cc_layer_for_testing()->bounds();
@@ -1945,6 +2153,57 @@ TEST_F(LayerWithDelegateTest, ExternalContentMirroring) {
EXPECT_EQ(surface_id, surface->surface_id());
}
+TEST_F(LayerWithDelegateTest, TransferableResourceMirroring) {
+ std::unique_ptr<Layer> layer(CreateLayer(LAYER_SOLID_COLOR));
+
+ auto resource = viz::TransferableResource::MakeGL(
+ gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken());
+ bool release_callback_run = false;
+
+ layer->SetTransferableResource(
+ resource,
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce(ReturnMailbox, &release_callback_run)),
+ gfx::Size(10, 10));
+ EXPECT_FALSE(release_callback_run);
+ EXPECT_TRUE(layer->has_external_content());
+
+ auto mirror = layer->Mirror();
+ EXPECT_TRUE(mirror->has_external_content());
+
+ // Clearing the resource on a mirror layer should not release the source layer
+ // resource.
+ mirror.reset();
+ EXPECT_FALSE(release_callback_run);
+
+ mirror = layer->Mirror();
+ EXPECT_TRUE(mirror->has_external_content());
+
+ // Clearing the transferable resource on the source layer should clear it from
+ // the mirror layer as well.
+ layer->SetShowSolidColorContent();
+ EXPECT_TRUE(release_callback_run);
+ EXPECT_FALSE(layer->has_external_content());
+ EXPECT_FALSE(mirror->has_external_content());
+
+ resource = viz::TransferableResource::MakeGL(
+ gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken());
+ release_callback_run = false;
+
+ // Setting a transferable resource on the source layer should set it on the
+ // mirror layers as well.
+ layer->SetTransferableResource(
+ resource,
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce(ReturnMailbox, &release_callback_run)),
+ gfx::Size(10, 10));
+ EXPECT_FALSE(release_callback_run);
+ EXPECT_TRUE(layer->has_external_content());
+ EXPECT_TRUE(mirror->has_external_content());
+
+ layer.reset();
+}
+
// Verifies that layer filters still attached after changing implementation
// layer.
TEST_F(LayerWithDelegateTest, LayerFiltersSurvival) {
@@ -2260,8 +2519,11 @@ TEST_F(LayerWithRealCompositorTest, SnapLayerToPixels) {
std::unique_ptr<Layer> c1(CreateLayer(LAYER_TEXTURED));
std::unique_ptr<Layer> c11(CreateLayer(LAYER_TEXTURED));
- GetCompositor()->SetScaleAndSize(1.25f, gfx::Size(100, 100),
- viz::LocalSurfaceIdAllocation());
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.25f, gfx::Size(100, 100),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
GetCompositor()->SetRootLayer(root.get());
root->Add(c1.get());
c1->Add(c11.get());
@@ -2274,8 +2536,10 @@ TEST_F(LayerWithRealCompositorTest, SnapLayerToPixels) {
EXPECT_EQ("0.40 0.40",
Vector2dFTo100thPrecisionString(c11->subpixel_position_offset()));
- GetCompositor()->SetScaleAndSize(1.5f, gfx::Size(100, 100),
- viz::LocalSurfaceIdAllocation());
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.5f, gfx::Size(100, 100),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
SnapLayerToPhysicalPixelBoundary(root.get(), c11.get());
// c11 must already be aligned at 1.5 scale.
EXPECT_EQ("0.00 0.00",
@@ -2295,8 +2559,11 @@ TEST_F(LayerWithRealCompositorTest, SnapLayerToPixelsWithScaleTransform) {
std::unique_ptr<Layer> c11(CreateLayer(LAYER_TEXTURED));
std::unique_ptr<Layer> c111(CreateLayer(LAYER_TEXTURED));
- GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(100, 100),
- viz::LocalSurfaceIdAllocation());
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ GetCompositor()->SetScaleAndSize(
+ 1.0f, gfx::Size(100, 100),
+ allocator.GetCurrentLocalSurfaceIdAllocation());
GetCompositor()->SetRootLayer(root.get());
root->Add(c1.get());
c1->Add(c11.get());
diff --git a/chromium/ui/compositor/paint_context.h b/chromium/ui/compositor/paint_context.h
index 96385275c43..63e5b75b7d0 100644
--- a/chromium/ui/compositor/paint_context.h
+++ b/chromium/ui/compositor/paint_context.h
@@ -19,7 +19,6 @@ class DisplayItemList;
namespace ui {
class ClipRecorder;
-class CompositingRecorder;
class PaintRecorder;
class TransformRecorder;
@@ -78,7 +77,6 @@ class COMPOSITOR_EXPORT PaintContext {
// don't want to expose them on this class so that people must go through the
// recorders to access them.
friend class ClipRecorder;
- friend class CompositingRecorder;
friend class PaintRecorder;
friend class TransformRecorder;
// The Cache class also needs to access the DisplayItemList to append its
diff --git a/chromium/ui/compositor/recyclable_compositor_mac.cc b/chromium/ui/compositor/recyclable_compositor_mac.cc
index 7f474063719..9aed2f269d0 100644
--- a/chromium/ui/compositor/recyclable_compositor_mac.cc
+++ b/chromium/ui/compositor/recyclable_compositor_mac.cc
@@ -44,7 +44,6 @@ RecyclableCompositorMac::RecyclableCompositorMac(
context_factory,
context_factory_private,
GetCompositorTaskRunner(),
- features::IsSurfaceSynchronizationEnabled(),
ui::IsPixelCanvasRecordingEnabled()) {
g_recyclable_compositor_count += 1;
compositor_.SetAcceleratedWidget(
diff --git a/chromium/ui/compositor/recyclable_compositor_mac.h b/chromium/ui/compositor/recyclable_compositor_mac.h
index adbb2d498ed..d9991afa341 100644
--- a/chromium/ui/compositor/recyclable_compositor_mac.h
+++ b/chromium/ui/compositor/recyclable_compositor_mac.h
@@ -56,11 +56,6 @@ class COMPOSITOR_EXPORT RecyclableCompositorMac
// ui::CompositorObserver implementation:
void OnCompositingDidCommit(ui::Compositor* compositor) override;
- void OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) override {}
- void OnCompositingEnded(ui::Compositor* compositor) override {}
- void OnCompositingChildResizing(ui::Compositor* compositor) override {}
- void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
std::unique_ptr<ui::AcceleratedWidgetMac> accelerated_widget_mac_;
ui::Compositor compositor_;
diff --git a/chromium/ui/compositor/test/test_compositor_host_ozone.cc b/chromium/ui/compositor/test/test_compositor_host_ozone.cc
index 5a97ed93e3a..3efd0450c9b 100644
--- a/chromium/ui/compositor/test/test_compositor_host_ozone.cc
+++ b/chromium/ui/compositor/test/test_compositor_host_ozone.cc
@@ -13,6 +13,7 @@
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "ui/compositor/compositor.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
@@ -72,6 +73,7 @@ class TestCompositorHostOzone : public TestCompositorHost {
ui::Compositor compositor_;
std::unique_ptr<PlatformWindow> window_;
StubPlatformWindowDelegate window_delegate_;
+ viz::ParentLocalSurfaceIdAllocator allocator_;
DISALLOW_COPY_AND_ASSIGN(TestCompositorHostOzone);
};
@@ -85,7 +87,6 @@ TestCompositorHostOzone::TestCompositorHostOzone(
context_factory,
context_factory_private,
base::ThreadTaskRunnerHandle::Get(),
- false /* enable_surface_synchronization */,
false /* enable_pixel_canvas */) {}
TestCompositorHostOzone::~TestCompositorHostOzone() {
@@ -103,9 +104,10 @@ void TestCompositorHostOzone::Show() {
window_->Show();
DCHECK_NE(window_delegate_.widget(), gfx::kNullAcceleratedWidget);
+ allocator_.GenerateId();
compositor_.SetAcceleratedWidget(window_delegate_.widget());
compositor_.SetScaleAndSize(1.0f, bounds_.size(),
- viz::LocalSurfaceIdAllocation());
+ allocator_.GetCurrentLocalSurfaceIdAllocation());
compositor_.SetVisible(true);
}
diff --git a/chromium/ui/display/mac/screen_mac.mm b/chromium/ui/display/mac/screen_mac.mm
index ff92b9fad59..96f17137071 100644
--- a/chromium/ui/display/mac/screen_mac.mm
+++ b/chromium/ui/display/mac/screen_mac.mm
@@ -16,7 +16,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
#include "base/mac/sdk_forward_declarations.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/timer/timer.h"
#include "ui/display/display.h"
#include "ui/display/display_change_notifier.h"
@@ -312,7 +312,7 @@ class ScreenMac : public Screen {
// doesn't hurt.
CGDirectDisplayID online_displays[128];
CGDisplayCount online_display_count = 0;
- if (CGGetOnlineDisplayList(arraysize(online_displays), online_displays,
+ if (CGGetOnlineDisplayList(base::size(online_displays), online_displays,
&online_display_count) != kCGErrorSuccess) {
return std::vector<Display>(1, BuildPrimaryDisplay());
}
diff --git a/chromium/ui/display/manager/configure_displays_task_unittest.cc b/chromium/ui/display/manager/configure_displays_task_unittest.cc
index a3e478cd5db..72ad4fe9170 100644
--- a/chromium/ui/display/manager/configure_displays_task_unittest.cc
+++ b/chromium/ui/display/manager/configure_displays_task_unittest.cc
@@ -5,9 +5,9 @@
#include <stddef.h>
#include "base/bind.h"
-#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/manager/configure_displays_task.h"
#include "ui/display/manager/fake_display_snapshot.h"
@@ -101,7 +101,7 @@ TEST_F(ConfigureDisplaysTaskTest, ConfigureWithTwoDisplay) {
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
std::vector<DisplayConfigureRequest> requests;
- for (size_t i = 0; i < arraysize(displays_); ++i) {
+ for (size_t i = 0; i < base::size(displays_); ++i) {
requests.push_back(DisplayConfigureRequest(
displays_[i].get(), displays_[i]->native_mode(), gfx::Point()));
}
@@ -166,7 +166,7 @@ TEST_F(ConfigureDisplaysTaskTest, ConfigureWithTwoDisplayFails) {
delegate_.set_max_configurable_pixels(1);
std::vector<DisplayConfigureRequest> requests;
- for (size_t i = 0; i < arraysize(displays_); ++i) {
+ for (size_t i = 0; i < base::size(displays_); ++i) {
requests.push_back(DisplayConfigureRequest(
displays_[i].get(), displays_[i]->native_mode(), gfx::Point()));
}
@@ -192,7 +192,7 @@ TEST_F(ConfigureDisplaysTaskTest, ConfigureWithTwoDisplaysPartialSuccess) {
delegate_.set_max_configurable_pixels(small_mode_.size().GetArea());
std::vector<DisplayConfigureRequest> requests;
- for (size_t i = 0; i < arraysize(displays_); ++i) {
+ for (size_t i = 0; i < base::size(displays_); ++i) {
requests.push_back(DisplayConfigureRequest(
displays_[i].get(), displays_[i]->native_mode(), gfx::Point()));
}
@@ -219,7 +219,7 @@ TEST_F(ConfigureDisplaysTaskTest, AsyncConfigureWithTwoDisplaysPartialSuccess) {
delegate_.set_max_configurable_pixels(small_mode_.size().GetArea());
std::vector<DisplayConfigureRequest> requests;
- for (size_t i = 0; i < arraysize(displays_); ++i) {
+ for (size_t i = 0; i < base::size(displays_); ++i) {
requests.push_back(DisplayConfigureRequest(
displays_[i].get(), displays_[i]->native_mode(), gfx::Point()));
}
diff --git a/chromium/ui/display/manager/display_change_observer.cc b/chromium/ui/display/manager/display_change_observer.cc
index e9064681170..e99d15e4240 100644
--- a/chromium/ui/display/manager/display_change_observer.cc
+++ b/chromium/ui/display/manager/display_change_observer.cc
@@ -12,6 +12,7 @@
#include <vector>
#include "base/logging.h"
+#include "base/stl_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/user_activity/user_activity_detector.h"
#include "ui/display/display.h"
@@ -199,15 +200,18 @@ void DisplayChangeObserver::OnDisplayModeChangeFailed(
OnDisplayModeChanged(displays);
}
-void DisplayChangeObserver::OnTouchscreenDeviceConfigurationChanged() {
- // If there are no cached display snapshots, either there are no attached
- // displays or the cached snapshots have been invalidated. For the first case
- // there aren't any touchscreens to associate. For the second case, the
- // displays and touch input-devices will get associated when display
- // configuration finishes.
- const auto& cached_displays = display_configurator_->cached_displays();
- if (!cached_displays.empty())
- OnDisplayModeChanged(cached_displays);
+void DisplayChangeObserver::OnInputDeviceConfigurationChanged(
+ uint8_t input_device_types) {
+ if (input_device_types & ui::InputDeviceEventObserver::kTouchscreen) {
+ // If there are no cached display snapshots, either there are no attached
+ // displays or the cached snapshots have been invalidated. For the first
+ // case there aren't any touchscreens to associate. For the second case,
+ // the displays and touch input-devices will get associated when display
+ // configuration finishes.
+ const auto& cached_displays = display_configurator_->cached_displays();
+ if (!cached_displays.empty())
+ OnDisplayModeChanged(cached_displays);
+ }
}
void DisplayChangeObserver::UpdateInternalDisplay(
@@ -313,7 +317,7 @@ ManagedDisplayInfo DisplayChangeObserver::CreateManagedDisplayInfo(
// static
float DisplayChangeObserver::FindDeviceScaleFactor(float dpi) {
- for (size_t i = 0; i < arraysize(kThresholdTableForInternal); ++i) {
+ for (size_t i = 0; i < base::size(kThresholdTableForInternal); ++i) {
if (dpi > kThresholdTableForInternal[i].dpi)
return kThresholdTableForInternal[i].device_scale_factor;
}
diff --git a/chromium/ui/display/manager/display_change_observer.h b/chromium/ui/display/manager/display_change_observer.h
index 7cafa0e9048..a81a5d83b95 100644
--- a/chromium/ui/display/manager/display_change_observer.h
+++ b/chromium/ui/display/manager/display_change_observer.h
@@ -55,7 +55,7 @@ class DISPLAY_MANAGER_EXPORT DisplayChangeObserver
MultipleDisplayState failed_new_state) override;
// Overriden from ui::InputDeviceEventObserver:
- void OnTouchscreenDeviceConfigurationChanged() override;
+ void OnInputDeviceConfigurationChanged(uint8_t input_device_types) override;
// Exposed for testing.
DISPLAY_EXPORT static float FindDeviceScaleFactor(float dpi);
diff --git a/chromium/ui/display/manager/display_configurator_unittest.cc b/chromium/ui/display/manager/display_configurator_unittest.cc
index cde72cc6654..2abdd1f804a 100644
--- a/chromium/ui/display/manager/display_configurator_unittest.cc
+++ b/chromium/ui/display/manager/display_configurator_unittest.cc
@@ -8,10 +8,10 @@
#include <stdint.h>
#include "base/command_line.h"
-#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
-#include "chromeos/chromeos_switches.h"
+#include "base/stl_util.h"
+#include "chromeos/constants/chromeos_switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/manager/fake_display_snapshot.h"
#include "ui/display/manager/test/action_logger_util.h"
@@ -287,7 +287,7 @@ class DisplayConfiguratorTest : public testing::Test {
// output-change events to |configurator_| and triggers the configure
// timeout if one was scheduled.
void UpdateOutputs(size_t num_outputs, bool send_events) {
- ASSERT_LE(num_outputs, arraysize(outputs_));
+ ASSERT_LE(num_outputs, base::size(outputs_));
std::vector<DisplaySnapshot*> outputs;
for (size_t i = 0; i < num_outputs; ++i)
outputs.push_back(outputs_[i].get());
diff --git a/chromium/ui/display/manager/display_manager.cc b/chromium/ui/display/manager/display_manager.cc
index 043235bbee0..43d520a6a9f 100644
--- a/chromium/ui/display/manager/display_manager.cc
+++ b/chromium/ui/display/manager/display_manager.cc
@@ -477,13 +477,19 @@ void DisplayManager::SetLayoutForCurrentDisplays(
}
const Display& DisplayManager::GetDisplayForId(int64_t display_id) const {
- Display* display =
+ auto* display =
const_cast<DisplayManager*>(this)->FindDisplayForId(display_id);
+ // TODO(oshima): This happens when windows in unified desktop have
+ // been moved to a normal window. Fix this.
+ if (!display && display_id != kUnifiedDisplayId)
+ DLOG(ERROR) << "Could not find display:" << display_id;
return display ? *display : GetInvalidDisplay();
}
bool DisplayManager::IsDisplayIdValid(int64_t display_id) const {
- return GetDisplayForId(display_id).is_valid();
+ Display* display =
+ const_cast<DisplayManager*>(this)->FindDisplayForId(display_id);
+ return !!display;
}
const Display& DisplayManager::FindDisplayContainingPoint(
@@ -1994,10 +2000,6 @@ Display* DisplayManager::FindDisplayForId(int64_t id) {
[id](const Display& display) { return display.id() == id; });
if (iter != active_display_list_.end())
return &(*iter);
- // TODO(oshima): This happens when windows in unified desktop have
- // been moved to a normal window. Fix this.
- if (id != kUnifiedDisplayId)
- DLOG(ERROR) << "Could not find display:" << id;
return nullptr;
}
diff --git a/chromium/ui/display/manager/display_manager.h b/chromium/ui/display/manager/display_manager.h
index 6b24e337e78..9efea19317e 100644
--- a/chromium/ui/display/manager/display_manager.h
+++ b/chromium/ui/display/manager/display_manager.h
@@ -514,7 +514,8 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
// Same as above but for Unified Desktop.
void CreateUnifiedDesktopDisplayInfo(DisplayInfoList* display_info_list);
- Display* FindDisplayForId(int64_t id);
+ // Finds an display for given |display_id|. Returns nullptr if not found.
+ Display* FindDisplayForId(int64_t display_id);
// Add the mirror display's display info if the software based mirroring is in
// use. This should only be called before UpdateDisplaysWith().
diff --git a/chromium/ui/display/manager/touch_device_manager.cc b/chromium/ui/display/manager/touch_device_manager.cc
index 41606b4eeb9..1c87c85a613 100644
--- a/chromium/ui/display/manager/touch_device_manager.cc
+++ b/chromium/ui/display/manager/touch_device_manager.cc
@@ -35,10 +35,17 @@ bool IsDeviceConnectedViaUsb(const base::FilePath& path) {
for (const auto& component : components) {
if (base::StartsWith(component, "usb",
- base::CompareCase::INSENSITIVE_ASCII))
+ base::CompareCase::INSENSITIVE_ASCII)) {
return true;
- }
+ }
+ // TODO(malaykeshav): When evdi starts registering with the usb subsystem
+ // in the kernel, this would no longer be needed. All evdi displays are USB
+ // right now. This might change in the future however.
+ // See https://crbug.com/923165 for more info.
+ if (base::StartsWith(component, "evdi", base::CompareCase::SENSITIVE))
+ return true;
+ }
return false;
}
diff --git a/chromium/ui/display/manager/touch_transform_controller.cc b/chromium/ui/display/manager/touch_transform_controller.cc
index 4b7602d035d..50b55ffaa13 100644
--- a/chromium/ui/display/manager/touch_transform_controller.cc
+++ b/chromium/ui/display/manager/touch_transform_controller.cc
@@ -9,7 +9,6 @@
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/display/display_layout.h"
-#include "ui/display/manager/display_configurator.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/manager/managed_display_info.h"
#include "ui/display/manager/touch_device_manager.h"
@@ -281,11 +280,9 @@ gfx::Transform TouchTransformController::GetTouchTransform(
}
TouchTransformController::TouchTransformController(
- DisplayConfigurator* display_configurator,
DisplayManager* display_manager,
std::unique_ptr<TouchTransformSetter> setter)
- : display_configurator_(display_configurator),
- display_manager_(display_manager),
+ : display_manager_(display_manager),
touch_transform_setter_(std::move(setter)) {}
TouchTransformController::~TouchTransformController() {}
diff --git a/chromium/ui/display/manager/touch_transform_controller.h b/chromium/ui/display/manager/touch_transform_controller.h
index 55de79d65df..00c7914aae6 100644
--- a/chromium/ui/display/manager/touch_transform_controller.h
+++ b/chromium/ui/display/manager/touch_transform_controller.h
@@ -22,7 +22,6 @@ struct TouchDeviceTransform;
namespace display {
-class DisplayConfigurator;
class DisplayManager;
class ManagedDisplayInfo;
class TouchTransformSetter;
@@ -38,8 +37,7 @@ class TouchTransformControllerTestApi;
// and input-device space.
class DISPLAY_MANAGER_EXPORT TouchTransformController {
public:
- TouchTransformController(DisplayConfigurator* display_configurator,
- DisplayManager* display_manager,
+ TouchTransformController(DisplayManager* display_manager,
std::unique_ptr<TouchTransformSetter> setter);
~TouchTransformController();
@@ -103,9 +101,7 @@ class DISPLAY_MANAGER_EXPORT TouchTransformController {
const ManagedDisplayInfo& target_display,
UpdateData* update_data) const;
- // Both |display_configurator_| and |display_manager_| are not owned and must
- // outlive TouchTransformController.
- DisplayConfigurator* display_configurator_;
+ // |display_manager_| are not owned and must outlive TouchTransformController.
DisplayManager* display_manager_;
bool is_calibrating_ = false;
diff --git a/chromium/ui/display/manager/touch_transform_controller_unittest.cc b/chromium/ui/display/manager/touch_transform_controller_unittest.cc
index ba7cdd1d88c..5cff31ff404 100644
--- a/chromium/ui/display/manager/touch_transform_controller_unittest.cc
+++ b/chromium/ui/display/manager/touch_transform_controller_unittest.cc
@@ -126,7 +126,7 @@ class TouchTransformControllerTest : public testing::Test {
display_manager_ = std::make_unique<DisplayManager>(std::move(screen));
touch_device_manager_ = display_manager_->touch_device_manager();
touch_transform_controller_ = std::make_unique<TouchTransformController>(
- nullptr, display_manager_.get(),
+ display_manager_.get(),
std::make_unique<DefaultTouchTransformSetter>());
}
diff --git a/chromium/ui/display/util/display_util.cc b/chromium/ui/display/util/display_util.cc
index ffb9cd123cf..f68e408b886 100644
--- a/chromium/ui/display/util/display_util.cc
+++ b/chromium/ui/display/util/display_util.cc
@@ -7,7 +7,7 @@
#include <stddef.h>
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
namespace display {
@@ -32,7 +32,7 @@ bool IsDisplaySizeBlackListed(const gfx::Size& physical_size) {
VLOG(1) << "Smaller than minimum display size";
return true;
}
- for (size_t i = 1; i < arraysize(kInvalidDisplaySizeList); ++i) {
+ for (size_t i = 1; i < base::size(kInvalidDisplaySizeList); ++i) {
const gfx::Size size(kInvalidDisplaySizeList[i][0],
kInvalidDisplaySizeList[i][1]);
if (physical_size == size) {
diff --git a/chromium/ui/display/util/edid_parser_unittest.cc b/chromium/ui/display/util/edid_parser_unittest.cc
index d113317e292..500e4a41585 100644
--- a/chromium/ui/display/util/edid_parser_unittest.cc
+++ b/chromium/ui/display/util/edid_parser_unittest.cc
@@ -8,8 +8,8 @@
#include <memory>
-#include "base/macros.h"
#include "base/numerics/ranges.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "ui/display/types/display_constants.h"
@@ -34,7 +34,7 @@ constexpr unsigned char kNormalDisplay[] =
"\x30\x20\x36\x00\x81\x90\x21\x00\x00\x1a\x00\x00\x00\xfc\x00\x48"
"\x50\x20\x5a\x52\x33\x30\x77\x0a\x20\x20\x20\x20\x00\x00\x00\xff"
"\x00\x43\x4e\x34\x32\x30\x32\x31\x33\x37\x51\x0a\x20\x20\x00\x71";
-constexpr size_t kNormalDisplayLength = arraysize(kNormalDisplay);
+constexpr size_t kNormalDisplayLength = base::size(kNormalDisplay);
constexpr unsigned char kInternalDisplay[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x4c\xa3\x42\x31\x00\x00\x00\x00"
@@ -45,7 +45,7 @@ constexpr unsigned char kInternalDisplay[] =
"\x00\x00\x00\x00\x00\x23\x87\x02\x64\x00\x00\x00\x00\xfe\x00\x53"
"\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x00\x00\x00\xfe"
"\x00\x31\x32\x31\x41\x54\x31\x31\x2d\x38\x30\x31\x0a\x20\x00\x45";
-constexpr size_t kInternalDisplayLength = arraysize(kInternalDisplay);
+constexpr size_t kInternalDisplayLength = base::size(kInternalDisplay);
constexpr unsigned char kOverscanDisplay[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x4c\x2d\xfe\x08\x00\x00\x00\x00"
@@ -64,7 +64,7 @@ constexpr unsigned char kOverscanDisplay[] =
"\x5a\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6";
-constexpr size_t kOverscanDisplayLength = arraysize(kOverscanDisplay);
+constexpr size_t kOverscanDisplayLength = base::size(kOverscanDisplay);
// The EDID info misdetecting overscan once. see crbug.com/226318
constexpr unsigned char kMisdetectedDisplay[] =
@@ -84,7 +84,7 @@ constexpr unsigned char kMisdetectedDisplay[] =
"\x72\x51\xd0\x1e\x20\x6e\x28\x55\x00\x81\x91\x21\x00\x00\x1e\x8c"
"\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\x81\x91\x21\x00\x00"
"\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94";
-constexpr size_t kMisdetectedDisplayLength = arraysize(kMisdetectedDisplay);
+constexpr size_t kMisdetectedDisplayLength = base::size(kMisdetectedDisplay);
constexpr unsigned char kLP2565A[] =
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x76\x26\x01\x01\x01\x01"
@@ -95,7 +95,7 @@ constexpr unsigned char kLP2565A[] =
"\x5E\x11\x00\x0A\x20\x20\x20\x20\x20\x20\x00\x00\x00\xFC\x00\x48"
"\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
"\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\xA4";
-constexpr size_t kLP2565ALength = arraysize(kLP2565A);
+constexpr size_t kLP2565ALength = base::size(kLP2565A);
constexpr unsigned char kLP2565B[] =
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x75\x26\x01\x01\x01\x01"
@@ -106,7 +106,7 @@ constexpr unsigned char kLP2565B[] =
"\x5E\x15\x00\x0A\x20\x20\x20\x20\x20\x20\x00\x00\x00\xFC\x00\x48"
"\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
"\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\x45";
-constexpr size_t kLP2565BLength = arraysize(kLP2565B);
+constexpr size_t kLP2565BLength = base::size(kLP2565B);
// HP z32x monitor.
constexpr unsigned char kHPz32x[] =
@@ -126,7 +126,7 @@ constexpr unsigned char kHPz32x[] =
"\x00\xA0\xA0\x40\x2E\x60\x20\x30\x63\x00\xB9\x88\x21\x00\x00\x1C"
"\x28\x3C\x80\xA0\x70\xB0\x23\x40\x30\x20\x36\x00\xB9\x88\x21\x00"
"\x00\x1A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3E";
-constexpr size_t kHPz32xLength = arraysize(kHPz32x);
+constexpr size_t kHPz32xLength = base::size(kHPz32x);
// Chromebook Samus internal display.
constexpr unsigned char kSamus[] =
@@ -138,7 +138,7 @@ constexpr unsigned char kSamus[] =
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\x00\x4c"
"\x47\x20\x44\x69\x73\x70\x6c\x61\x79\x0a\x20\x20\x00\x00\x00\xfe"
"\x00\x4c\x50\x31\x32\x39\x51\x45\x32\x2d\x53\x50\x41\x31\x00\x6c";
-constexpr size_t kSamusLength = arraysize(kSamus);
+constexpr size_t kSamusLength = base::size(kSamus);
// Chromebook Eve internal display.
constexpr unsigned char kEve[] =
@@ -150,7 +150,7 @@ constexpr unsigned char kEve[] =
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc"
"\x00\x4c\x51\x31\x32\x33\x50\x31\x4a\x58\x33\x32\x0a\x20\x00\xb6";
-constexpr size_t kEveLength = arraysize(kEve);
+constexpr size_t kEveLength = base::size(kEve);
// Primaries coordinates ({RX, RY, GX, GY, BX, BY, WX, WY}) calculated by hand
// and rounded to 4 decimal places.
diff --git a/chromium/ui/display/win/screen_win.cc b/chromium/ui/display/win/screen_win.cc
index 7fd3b5b4a78..cb17d76dd94 100644
--- a/chromium/ui/display/win/screen_win.cc
+++ b/chromium/ui/display/win/screen_win.cc
@@ -70,7 +70,8 @@ int GetPerMonitorDPI(HMONITOR monitor) {
//
// Respects the forced device scale factor, and will fall back to the global
// scale factor if per-monitor DPI is not supported.
-float GetMonitorScaleFactorImpl(HMONITOR monitor, bool include_accessibility) {
+float GetMonitorScaleFactor(HMONITOR monitor,
+ bool include_accessibility = true) {
DCHECK(monitor);
if (Display::HasForceDeviceScaleFactor())
return Display::GetForcedDeviceScaleFactor();
@@ -88,19 +89,6 @@ float GetMonitorScaleFactorImpl(HMONITOR monitor, bool include_accessibility) {
return scale_factor;
}
-// Rounds a scale factor to one we can display safely in pixels without
-// smearing.
-double RoundToNearestSafeScaleFactor(float scale_factor) {
- return std::max(1.0f, std::round(4.0f * scale_factor) * 0.25f);
-}
-
-// Returns a pixel safe monitor scale factor rounded to a pixel-safe value.
-float GetSafeMonitorScaleFactor(HMONITOR monitor,
- bool include_accessibility = true) {
- return RoundToNearestSafeScaleFactor(
- GetMonitorScaleFactorImpl(monitor, include_accessibility));
-}
-
bool GetPathInfo(HMONITOR monitor, DISPLAYCONFIG_PATH_INFO* path_info) {
LONG result;
uint32_t num_path_array_elements = 0;
@@ -292,7 +280,7 @@ BOOL CALLBACK EnumMonitorForDisplayInfoCallback(HMONITOR monitor,
reinterpret_cast<std::vector<DisplayInfo>*>(data);
DCHECK(display_infos);
display_infos->push_back(DisplayInfo(MonitorInfoFromHMONITOR(monitor),
- GetSafeMonitorScaleFactor(monitor),
+ GetMonitorScaleFactor(monitor),
GetMonitorSDRWhiteLevel(monitor)));
return TRUE;
}
@@ -480,8 +468,7 @@ int ScreenWin::GetSystemMetricsForMonitor(HMONITOR monitor, int metric) {
if (!monitor)
monitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
- float scale_factor =
- GetSafeMonitorScaleFactor(monitor, include_accessibility);
+ float scale_factor = GetMonitorScaleFactor(monitor, include_accessibility);
// We'll then pull up the system metrics scaled by the appropriate amount.
return GetSystemMetricsForScaleFactor(scale_factor, metric);
@@ -519,9 +506,8 @@ int ScreenWin::GetDPIForHWND(HWND hwnd) {
// static
float ScreenWin::GetScaleFactorForDPI(int dpi) {
- return RoundToNearestSafeScaleFactor(
- display::win::internal::GetScalingFactorFromDPI(dpi) *
- UwpTextScaleFactor::Instance()->GetTextScaleFactor());
+ return display::win::internal::GetScalingFactorFromDPI(dpi) *
+ UwpTextScaleFactor::Instance()->GetTextScaleFactor();
}
// static
diff --git a/chromium/ui/events/BUILD.gn b/chromium/ui/events/BUILD.gn
index 278550b665b..f9227d744a2 100644
--- a/chromium/ui/events/BUILD.gn
+++ b/chromium/ui/events/BUILD.gn
@@ -327,7 +327,7 @@ jumbo_component("events") {
"fuchsia/input_event_dispatcher_delegate.h",
]
sources += [ "fuchsia/input_event_dispatcher.cc" ]
- public_deps += [ "//third_party/fuchsia-sdk/sdk:input" ]
+ public_deps += [ "//third_party/fuchsia-sdk/sdk:ui_input" ]
}
}
@@ -618,7 +618,7 @@ if (!is_ios) {
if (is_fuchsia) {
sources += [ "fuchsia/input_event_dispatcher_unittest.cc" ]
- deps += [ "//third_party/fuchsia-sdk/sdk:input" ]
+ deps += [ "//third_party/fuchsia-sdk/sdk:ui_input" ]
}
}
}
diff --git a/chromium/ui/events/blink/OWNERS b/chromium/ui/events/blink/OWNERS
index 5becb59f9da..c81e7a79ef7 100644
--- a/chromium/ui/events/blink/OWNERS
+++ b/chromium/ui/events/blink/OWNERS
@@ -1,5 +1,7 @@
dtapuska@chromium.org
tdresser@chromium.org
+bokan@chromium.org
+nzolghadr@chromium.org
# TEAM: input-dev@chromium.org
# COMPONENT: Blink>Input
diff --git a/chromium/ui/events/blink/blink_event_util.cc b/chromium/ui/events/blink/blink_event_util.cc
index a2108c64397..7a3bae1a40e 100644
--- a/chromium/ui/events/blink/blink_event_util.cc
+++ b/chromium/ui/events/blink/blink_event_util.cc
@@ -456,9 +456,16 @@ bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
// GesturePinchUpdate scales can be combined only if they share a focal point,
// e.g., with double-tap drag zoom.
+ // Due to the imprecision of OOPIF coordinate conversions, the positions may
+ // not be exactly equal, so we only require approximate equality.
+ constexpr float kAnchorTolerance = 1.f;
if (event.GetType() == WebInputEvent::kGesturePinchUpdate &&
- event.PositionInWidget() == event_to_coalesce.PositionInWidget())
+ (std::abs(event.PositionInWidget().x -
+ event_to_coalesce.PositionInWidget().x) < kAnchorTolerance) &&
+ (std::abs(event.PositionInWidget().y -
+ event_to_coalesce.PositionInWidget().y) < kAnchorTolerance)) {
return true;
+ }
return false;
}
@@ -575,9 +582,10 @@ void Coalesce(const blink::WebInputEvent& event_to_coalesce,
}
}
-// Whether |event_in_queue| is GesturePinchUpdate or GestureScrollUpdate and
-// has the same modifiers/source as the new scroll/pinch event. Compatible
-// scroll and pinch event pairs can be logically coalesced.
+// Whether |event_in_queue| is a touchscreen GesturePinchUpdate or
+// GestureScrollUpdate and has the same modifiers/source as the new
+// scroll/pinch event. Compatible touchscreen scroll and pinch event pairs
+// can be logically coalesced.
bool IsCompatibleScrollorPinch(const WebGestureEvent& new_event,
const WebGestureEvent& event_in_queue) {
DCHECK(new_event.GetType() == WebInputEvent::kGestureScrollUpdate ||
@@ -589,7 +597,8 @@ bool IsCompatibleScrollorPinch(const WebGestureEvent& new_event,
return (event_in_queue.GetType() == WebInputEvent::kGestureScrollUpdate ||
event_in_queue.GetType() == WebInputEvent::kGesturePinchUpdate) &&
event_in_queue.GetModifiers() == new_event.GetModifiers() &&
- event_in_queue.SourceDevice() == new_event.SourceDevice();
+ event_in_queue.SourceDevice() == blink::kWebGestureDeviceTouchscreen &&
+ new_event.SourceDevice() == blink::kWebGestureDeviceTouchscreen;
}
std::pair<WebGestureEvent, WebGestureEvent> CoalesceScrollAndPinch(
diff --git a/chromium/ui/events/blink/blink_event_util_unittest.cc b/chromium/ui/events/blink/blink_event_util_unittest.cc
index 7e1af81fb07..dc23a7ee65f 100644
--- a/chromium/ui/events/blink/blink_event_util_unittest.cc
+++ b/chromium/ui/events/blink/blink_event_util_unittest.cc
@@ -226,6 +226,56 @@ TEST(BlinkEventUtilTest, WebGestureEventCoalescing) {
EXPECT_FALSE(CanCoalesce(event_to_be_coalesced, coalesced_event));
}
+TEST(BlinkEventUtilTest, GesturePinchUpdateCoalescing) {
+ gfx::PointF position(10.f, 10.f);
+ blink::WebGestureEvent coalesced_event(
+ blink::WebInputEvent::kGesturePinchUpdate,
+ blink::WebInputEvent::kNoModifiers,
+ blink::WebInputEvent::GetStaticTimeStampForTests(),
+ blink::kWebGestureDeviceTouchpad);
+ coalesced_event.data.pinch_update.scale = 1.1f;
+ coalesced_event.SetPositionInWidget(position);
+
+ blink::WebGestureEvent event_to_be_coalesced(coalesced_event);
+
+ ASSERT_TRUE(CanCoalesce(event_to_be_coalesced, coalesced_event));
+ Coalesce(event_to_be_coalesced, &coalesced_event);
+ EXPECT_FLOAT_EQ(1.21, coalesced_event.data.pinch_update.scale);
+
+ // Allow the updates to be coalesced if the anchors are nearly equal.
+ position.Offset(0.1f, 0.1f);
+ event_to_be_coalesced.SetPositionInWidget(position);
+ coalesced_event.data.pinch_update.scale = 1.1f;
+ ASSERT_TRUE(CanCoalesce(event_to_be_coalesced, coalesced_event));
+ Coalesce(event_to_be_coalesced, &coalesced_event);
+ EXPECT_FLOAT_EQ(1.21, coalesced_event.data.pinch_update.scale);
+
+ // The anchors are no longer considered equal, so don't coalesce.
+ position.Offset(1.f, 1.f);
+ event_to_be_coalesced.SetPositionInWidget(position);
+ EXPECT_FALSE(CanCoalesce(event_to_be_coalesced, coalesced_event));
+
+ // Don't logically coalesce touchpad pinch events as touchpad pinch events
+ // don't occur within a gesture scroll sequence.
+ EXPECT_FALSE(
+ IsCompatibleScrollorPinch(event_to_be_coalesced, coalesced_event));
+
+ // Touchscreen pinch events can be logically coalesced.
+ coalesced_event.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+ event_to_be_coalesced.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+ coalesced_event.data.pinch_update.scale = 1.1f;
+ ASSERT_TRUE(
+ IsCompatibleScrollorPinch(event_to_be_coalesced, coalesced_event));
+
+ blink::WebGestureEvent logical_scroll, logical_pinch;
+ std::tie(logical_scroll, logical_pinch) =
+ CoalesceScrollAndPinch(nullptr, coalesced_event, event_to_be_coalesced);
+ ASSERT_EQ(blink::WebInputEvent::kGestureScrollUpdate,
+ logical_scroll.GetType());
+ ASSERT_EQ(blink::WebInputEvent::kGesturePinchUpdate, logical_pinch.GetType());
+ EXPECT_FLOAT_EQ(1.21, logical_pinch.data.pinch_update.scale);
+}
+
TEST(BlinkEventUtilTest, MouseEventCoalescing) {
blink::WebMouseEvent coalesced_event;
coalesced_event.SetType(blink::WebInputEvent::kMouseMove);
diff --git a/chromium/ui/events/blink/compositor_thread_event_queue.cc b/chromium/ui/events/blink/compositor_thread_event_queue.cc
index d2796793b49..f9c2b460912 100644
--- a/chromium/ui/events/blink/compositor_thread_event_queue.cc
+++ b/chromium/ui/events/blink/compositor_thread_event_queue.cc
@@ -19,8 +19,9 @@ void CompositorThreadEventQueue::Queue(
base::TimeTicks timestamp_now) {
if (queue_.empty() ||
!IsContinuousGestureEvent(new_event->event().GetType()) ||
- !IsCompatibleScrollorPinch(ToWebGestureEvent(new_event->event()),
- ToWebGestureEvent(queue_.back()->event()))) {
+ !(queue_.back()->CanCoalesceWith(*new_event) ||
+ IsCompatibleScrollorPinch(ToWebGestureEvent(new_event->event()),
+ ToWebGestureEvent(queue_.back()->event())))) {
if (new_event->first_original_event()) {
// Trace could be nested as there might be multiple events in queue.
// e.g. |ScrollUpdate|, |ScrollEnd|, and another scroll sequence.
diff --git a/chromium/ui/events/blink/input_handler_proxy.cc b/chromium/ui/events/blink/input_handler_proxy.cc
index 7bb88f69628..72fdfaf83a9 100644
--- a/chromium/ui/events/blink/input_handler_proxy.cc
+++ b/chromium/ui/events/blink/input_handler_proxy.cc
@@ -43,8 +43,6 @@ namespace {
const int32_t kEventDispositionUndefined = -1;
-const size_t kTenSeconds = 10 * 1000 * 1000;
-
cc::ScrollState CreateScrollStateForGesture(const WebGestureEvent& event) {
cc::ScrollStateData scroll_state_data;
switch (event.GetType()) {
@@ -198,8 +196,7 @@ void InputHandlerProxy::HandleInputEventWithLatencyInfo(
// Note: Other input can race ahead of gesture input as they don't have to go
// through the queue, but we believe it's OK to do so.
- if (!compositor_event_queue_ ||
- !IsGestureScrollOrPinch(event_with_callback->event().GetType())) {
+ if (!IsGestureScrollOrPinch(event_with_callback->event().GetType())) {
DispatchSingleInputEvent(std::move(event_with_callback),
tick_clock_->NowTicks());
return;
@@ -254,33 +251,6 @@ void InputHandlerProxy::HandleInputEventWithLatencyInfo(
void InputHandlerProxy::DispatchSingleInputEvent(
std::unique_ptr<EventWithCallback> event_with_callback,
const base::TimeTicks now) {
- if (compositor_event_queue_ &&
- IsGestureScrollOrPinch(event_with_callback->event().GetType())) {
- // Report the coalesced count only for continuous events to avoid the noise
- // from non-continuous events.
- if (IsContinuousGestureEvent(event_with_callback->event().GetType())) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.CompositorThreadEventQueue.Continuous.HeadQueueingTime",
- (now - event_with_callback->creation_timestamp()).InMicroseconds(), 1,
- kTenSeconds, 50);
-
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.CompositorThreadEventQueue.Continuous.TailQueueingTime",
- (now - event_with_callback->last_coalesced_timestamp())
- .InMicroseconds(),
- 1, kTenSeconds, 50);
-
- UMA_HISTOGRAM_COUNTS_1000(
- "Event.CompositorThreadEventQueue.CoalescedCount",
- static_cast<int>(event_with_callback->coalesced_count()));
- } else {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.CompositorThreadEventQueue.NonContinuous.QueueingTime",
- (now - event_with_callback->creation_timestamp()).InMicroseconds(), 1,
- kTenSeconds, 50);
- }
- }
-
ui::LatencyInfo monitored_latency_info = event_with_callback->latency_info();
std::unique_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor =
input_handler_->CreateLatencyInfoSwapPromiseMonitor(
@@ -315,9 +285,6 @@ void InputHandlerProxy::DispatchSingleInputEvent(
}
void InputHandlerProxy::DispatchQueuedInputEvents() {
- if (!compositor_event_queue_)
- return;
-
// Calling |NowTicks()| is expensive so we only want to do it once.
base::TimeTicks now = tick_clock_->NowTicks();
while (!compositor_event_queue_->empty()) {
@@ -582,7 +549,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin(
const WebGestureEvent& gesture_event) {
TRACE_EVENT0("input", "InputHandlerProxy::HandleGestureScrollBegin");
- if (compositor_event_queue_ && scroll_predictor_)
+ if (scroll_predictor_)
scroll_predictor_->ResetOnGestureScrollBegin(gesture_event);
#if DCHECK_IS_ON()
diff --git a/chromium/ui/events/blink/input_handler_proxy.h b/chromium/ui/events/blink/input_handler_proxy.h
index 60175cc13da..7a378aadf5c 100644
--- a/chromium/ui/events/blink/input_handler_proxy.h
+++ b/chromium/ui/events/blink/input_handler_proxy.h
@@ -7,7 +7,6 @@
#include <memory>
-#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "cc/input/input_handler.h"
#include "cc/input/snap_fling_controller.h"
diff --git a/chromium/ui/events/blink/input_handler_proxy_unittest.cc b/chromium/ui/events/blink/input_handler_proxy_unittest.cc
index 39e30dd7360..2c81c8a54a5 100644
--- a/chromium/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/chromium/ui/events/blink/input_handler_proxy_unittest.cc
@@ -49,15 +49,6 @@ namespace test {
namespace {
-const char* kCoalescedCountHistogram =
- "Event.CompositorThreadEventQueue.CoalescedCount";
-const char* kContinuousHeadQueueingTimeHistogram =
- "Event.CompositorThreadEventQueue.Continuous.HeadQueueingTime";
-const char* kContinuousTailQueueingTimeHistogram =
- "Event.CompositorThreadEventQueue.Continuous.TailQueueingTime";
-const char* kNonContinuousQueueingTimeHistogram =
- "Event.CompositorThreadEventQueue.NonContinuous.QueueingTime";
-
enum InputHandlerProxyTestType {
ROOT_SCROLL_NORMAL_HANDLER,
ROOT_SCROLL_SYNCHRONOUS_HANDLER,
@@ -1406,8 +1397,6 @@ TEST(SynchronousInputHandlerProxyTest, SetOffset) {
}
TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScroll) {
- base::HistogramTester histogram_tester;
-
// Handle scroll on compositor.
cc::InputHandlerScrollResult scroll_result_did_scroll_;
scroll_result_did_scroll_.did_scroll = true;
@@ -1465,12 +1454,9 @@ TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScroll) {
EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[2]);
EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[3]);
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
- histogram_tester.ExpectUniqueSample(kCoalescedCountHistogram, 2, 1);
}
TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScrollPinchScroll) {
- base::HistogramTester histogram_tester;
-
// Handle scroll on compositor.
cc::InputHandlerScrollResult scroll_result_did_scroll_;
scroll_result_did_scroll_.did_scroll = true;
@@ -1530,12 +1516,9 @@ TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScrollPinchScroll) {
EXPECT_EQ(0ul, event_queue().size());
EXPECT_EQ(12ul, event_disposition_recorder_.size());
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
- histogram_tester.ExpectBucketCount(kCoalescedCountHistogram, 1, 2);
- histogram_tester.ExpectBucketCount(kCoalescedCountHistogram, 2, 2);
}
TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedQueueingTime) {
- base::HistogramTester histogram_tester;
base::SimpleTestTickClock tick_clock;
tick_clock.SetNowTicks(base::TimeTicks::Now());
SetInputHandlerProxyTickClockForTesting(&tick_clock);
@@ -1569,13 +1552,6 @@ TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedQueueingTime) {
EXPECT_EQ(0ul, event_queue().size());
EXPECT_EQ(5ul, event_disposition_recorder_.size());
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
- histogram_tester.ExpectUniqueSample(kContinuousHeadQueueingTimeHistogram, 140,
- 1);
- histogram_tester.ExpectUniqueSample(kContinuousTailQueueingTimeHistogram, 80,
- 1);
- histogram_tester.ExpectBucketCount(kNonContinuousQueueingTimeHistogram, 0, 1);
- histogram_tester.ExpectBucketCount(kNonContinuousQueueingTimeHistogram, 70,
- 1);
}
TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceScrollAndPinch) {
@@ -1645,6 +1621,41 @@ TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceScrollAndPinch) {
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
}
+TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceTouchpadPinch) {
+ EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
+ EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
+
+ HandleGestureEventWithSourceDevice(WebInputEvent::kGesturePinchBegin,
+ blink::kWebGestureDeviceTouchpad);
+ HandleGestureEventWithSourceDevice(WebInputEvent::kGesturePinchUpdate,
+ blink::kWebGestureDeviceTouchpad, 1.1f, 10,
+ 20);
+ // The second update should coalesce with the first.
+ HandleGestureEventWithSourceDevice(WebInputEvent::kGesturePinchUpdate,
+ blink::kWebGestureDeviceTouchpad, 1.1f, 10,
+ 20);
+ // The third update has a different anchor so it should not be coalesced.
+ HandleGestureEventWithSourceDevice(WebInputEvent::kGesturePinchUpdate,
+ blink::kWebGestureDeviceTouchpad, 1.1f, 11,
+ 21);
+ HandleGestureEventWithSourceDevice(WebInputEvent::kGesturePinchEnd,
+ blink::kWebGestureDeviceTouchpad);
+
+ // Only the PinchBegin was dispatched.
+ EXPECT_EQ(3ul, event_queue().size());
+ EXPECT_EQ(1ul, event_disposition_recorder_.size());
+
+ ASSERT_EQ(WebInputEvent::kGesturePinchUpdate,
+ event_queue()[0]->event().GetType());
+ EXPECT_FLOAT_EQ(
+ 1.21f,
+ ToWebGestureEvent(event_queue()[0]->event()).data.pinch_update.scale);
+ EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
+ event_queue()[1]->event().GetType());
+ EXPECT_EQ(WebInputEvent::kGesturePinchEnd,
+ event_queue()[2]->event().GetType());
+}
+
TEST_F(InputHandlerProxyEventQueueTest, OriginalEventsTracing) {
// Handle scroll on compositor.
cc::InputHandlerScrollResult scroll_result_did_scroll_;
@@ -2151,7 +2162,7 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) {
blink::kWebGestureDeviceTouchpad,
cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects |
cc::MainThreadScrollingReason::kThreadedScrollingDisabled |
- cc::MainThreadScrollingReason::kPageOverlay |
+ cc::MainThreadScrollingReason::kFrameOverlay |
cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
EXPECT_THAT(
@@ -2166,7 +2177,7 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) {
cc::MainThreadScrollingReason::kThreadedScrollingDisabled),
1),
base::Bucket(
- GetBucketSample(cc::MainThreadScrollingReason::kPageOverlay),
+ GetBucketSample(cc::MainThreadScrollingReason::kFrameOverlay),
1)));
// We only want to record "Handling scroll from main thread" reason if it's
@@ -2190,7 +2201,7 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) {
cc::MainThreadScrollingReason::kThreadedScrollingDisabled),
1),
base::Bucket(
- GetBucketSample(cc::MainThreadScrollingReason::kPageOverlay), 1),
+ GetBucketSample(cc::MainThreadScrollingReason::kFrameOverlay), 1),
base::Bucket(
GetBucketSample(
cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
diff --git a/chromium/ui/events/blink/web_input_event.cc b/chromium/ui/events/blink/web_input_event.cc
index 5f318baf91e..14e8ce56b1b 100644
--- a/chromium/ui/events/blink/web_input_event.cc
+++ b/chromium/ui/events/blink/web_input_event.cc
@@ -11,7 +11,6 @@
#include "ui/events/event_target.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
-#include "ui/events/keycodes/keyboard_code_conversion.h"
#if defined(OS_WIN)
#include "ui/events/blink/web_input_event_builders_win.h"
@@ -105,12 +104,7 @@ blink::WebKeyboardEvent MakeWebKeyboardEventFromUiEvent(const KeyEvent& event) {
if (webkit_event.GetModifiers() & blink::WebInputEvent::kAltKey)
webkit_event.is_system_key = true;
-
- // TODO(dtapuska): crbug.com/570388. Ozone appears to deliver
- // key_code events that aren't "located" for the keypad like
- // Windows and X11 do and blink expects.
- webkit_event.windows_key_code =
- NonLocatedToLocatedKeypadKeyboardCode(event.key_code(), event.code());
+ webkit_event.windows_key_code = event.key_code();
webkit_event.native_key_code =
KeycodeConverter::DomCodeToNativeKeycode(event.code());
webkit_event.dom_code = static_cast<int>(event.code());
diff --git a/chromium/ui/events/blink/web_input_event_unittest.cc b/chromium/ui/events/blink/web_input_event_unittest.cc
index c304c997ff4..2fb4ebf9bcd 100644
--- a/chromium/ui/events/blink/web_input_event_unittest.cc
+++ b/chromium/ui/events/blink/web_input_event_unittest.cc
@@ -7,7 +7,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
@@ -206,7 +206,7 @@ TEST(WebInputEventTest, TestMakeWebKeyboardEventKeyPadKeyCode) {
}
#if defined(USE_X11)
ScopedXI2Event xev;
- for (size_t i = 0; i < arraysize(kTesCases); ++i) {
+ for (size_t i = 0; i < base::size(kTesCases); ++i) {
const TestCase& test_case = kTesCases[i];
// TODO: re-enable the two cases excluded here once all trybots
@@ -472,7 +472,7 @@ TEST(WebInputEventTest, KeyEvent) {
{ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_C, ui::EF_ALT_DOWN),
blink::WebInputEvent::kKeyUp, blink::WebInputEvent::kAltKey}};
- for (size_t i = 0; i < arraysize(tests); i++) {
+ for (size_t i = 0; i < base::size(tests); i++) {
blink::WebKeyboardEvent web_event = MakeWebKeyboardEvent(tests[i].event);
ASSERT_TRUE(blink::WebInputEvent::IsKeyboardEventType(web_event.GetType()));
ASSERT_EQ(tests[i].web_type, web_event.GetType());
@@ -517,7 +517,7 @@ TEST(WebInputEventTest, MousePointerEvent) {
gfx::Point(13, 3), gfx::Point(53, 3)},
};
- for (size_t i = 0; i < arraysize(tests); i++) {
+ for (size_t i = 0; i < base::size(tests); i++) {
ui::MouseEvent ui_event(tests[i].ui_type, tests[i].location,
tests[i].screen_location, base::TimeTicks(),
tests[i].ui_modifiers, 0);
diff --git a/chromium/ui/events/devices/device_data_manager.cc b/chromium/ui/events/devices/device_data_manager.cc
index 86b8ebd0dad..dafd876afa1 100644
--- a/chromium/ui/events/devices/device_data_manager.cc
+++ b/chromium/ui/events/devices/device_data_manager.cc
@@ -228,17 +228,21 @@ void DeviceDataManager::OnStylusStateChanged(StylusState state) {
NotifyObserversStylusStateChanged(state);
}
-NOTIFY_OBSERVERS(NotifyObserversTouchscreenDeviceConfigurationChanged(),
- OnTouchscreenDeviceConfigurationChanged());
+NOTIFY_OBSERVERS(
+ NotifyObserversKeyboardDeviceConfigurationChanged(),
+ OnInputDeviceConfigurationChanged(InputDeviceEventObserver::kKeyboard));
-NOTIFY_OBSERVERS(NotifyObserversKeyboardDeviceConfigurationChanged(),
- OnKeyboardDeviceConfigurationChanged());
+NOTIFY_OBSERVERS(
+ NotifyObserversMouseDeviceConfigurationChanged(),
+ OnInputDeviceConfigurationChanged(InputDeviceEventObserver::kMouse));
-NOTIFY_OBSERVERS(NotifyObserversMouseDeviceConfigurationChanged(),
- OnMouseDeviceConfigurationChanged());
+NOTIFY_OBSERVERS(
+ NotifyObserversTouchpadDeviceConfigurationChanged(),
+ OnInputDeviceConfigurationChanged(InputDeviceEventObserver::kTouchpad));
-NOTIFY_OBSERVERS(NotifyObserversTouchpadDeviceConfigurationChanged(),
- OnTouchpadDeviceConfigurationChanged());
+NOTIFY_OBSERVERS(
+ NotifyObserversTouchscreenDeviceConfigurationChanged(),
+ OnInputDeviceConfigurationChanged(InputDeviceEventObserver::kTouchscreen));
NOTIFY_OBSERVERS(NotifyObserversDeviceListsComplete(), OnDeviceListsComplete());
diff --git a/chromium/ui/events/devices/input_device_event_observer.h b/chromium/ui/events/devices/input_device_event_observer.h
index c2507b93999..6310592ebc2 100644
--- a/chromium/ui/events/devices/input_device_event_observer.h
+++ b/chromium/ui/events/devices/input_device_event_observer.h
@@ -5,6 +5,8 @@
#ifndef UI_EVENTS_DEVICES_INPUT_DEVICE_EVENT_OBSERVER_H_
#define UI_EVENTS_DEVICES_INPUT_DEVICE_EVENT_OBSERVER_H_
+#include <stdint.h>
+
#include "ui/events/devices/events_devices_export.h"
namespace ui {
@@ -14,12 +16,19 @@ enum class StylusState;
// DeviceDataManager observer used to announce input hotplug events.
class EVENTS_DEVICES_EXPORT InputDeviceEventObserver {
public:
+ // Bitfields for input device types to update through
+ // |OnInputDeviceConfigurationChanged|.
+ static constexpr uint8_t kKeyboard = 1 << 0;
+ static constexpr uint8_t kMouse = 1 << 1;
+ static constexpr uint8_t kTouchpad = 1 << 2;
+ static constexpr uint8_t kTouchscreen = 1 << 3;
+
virtual ~InputDeviceEventObserver() {}
- virtual void OnKeyboardDeviceConfigurationChanged() {}
- virtual void OnTouchscreenDeviceConfigurationChanged() {}
- virtual void OnMouseDeviceConfigurationChanged() {}
- virtual void OnTouchpadDeviceConfigurationChanged() {}
+ // This method is called for configurations changes in the device types
+ // specified in |input_device_types| bit-field.
+ virtual void OnInputDeviceConfigurationChanged(uint8_t input_device_types) {}
+
virtual void OnDeviceListsComplete() {}
virtual void OnStylusStateChanged(StylusState state) {}
diff --git a/chromium/ui/events/devices/input_device_observer_android.cc b/chromium/ui/events/devices/input_device_observer_android.cc
index 05a6afc4cc6..fe057e351dc 100644
--- a/chromium/ui/events/devices/input_device_observer_android.cc
+++ b/chromium/ui/events/devices/input_device_observer_android.cc
@@ -10,13 +10,6 @@
using base::android::AttachCurrentThread;
using base::android::JavaParamRef;
-// This macro provides the implementation for the observer notification methods.
-#define NOTIFY_ANDROID_OBSERVERS(method_decl, observer_call) \
- void InputDeviceObserverAndroid::method_decl { \
- for (ui::InputDeviceEventObserver & observer : observers_) \
- observer.observer_call; \
- }
-
namespace ui {
InputDeviceObserverAndroid::InputDeviceObserverAndroid() {}
@@ -47,18 +40,14 @@ static void JNI_InputDeviceObserver_InputConfigurationChanged(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
InputDeviceObserverAndroid::GetInstance()
- ->NotifyObserversTouchpadDeviceConfigurationChanged();
- InputDeviceObserverAndroid::GetInstance()
- ->NotifyObserversKeyboardDeviceConfigurationChanged();
- InputDeviceObserverAndroid::GetInstance()
- ->NotifyObserversMouseDeviceConfigurationChanged();
+ ->NotifyObserversDeviceConfigurationChanged();
}
-NOTIFY_ANDROID_OBSERVERS(NotifyObserversMouseDeviceConfigurationChanged(),
- OnMouseDeviceConfigurationChanged());
-NOTIFY_ANDROID_OBSERVERS(NotifyObserversTouchpadDeviceConfigurationChanged(),
- OnTouchpadDeviceConfigurationChanged());
-NOTIFY_ANDROID_OBSERVERS(NotifyObserversKeyboardDeviceConfigurationChanged(),
- OnKeyboardDeviceConfigurationChanged());
+void InputDeviceObserverAndroid::NotifyObserversDeviceConfigurationChanged() {
+ for (ui::InputDeviceEventObserver& observer : observers_)
+ observer.OnInputDeviceConfigurationChanged(
+ InputDeviceEventObserver::kMouse | InputDeviceEventObserver::kKeyboard |
+ InputDeviceEventObserver::kTouchpad);
+}
} // namespace ui
diff --git a/chromium/ui/events/devices/input_device_observer_android.h b/chromium/ui/events/devices/input_device_observer_android.h
index 2e896d0a24e..bea4121ceff 100644
--- a/chromium/ui/events/devices/input_device_observer_android.h
+++ b/chromium/ui/events/devices/input_device_observer_android.h
@@ -28,9 +28,7 @@ class EVENTS_DEVICES_EXPORT InputDeviceObserverAndroid {
void AddObserver(ui::InputDeviceEventObserver* observer);
void RemoveObserver(ui::InputDeviceEventObserver* observer);
- void NotifyObserversTouchpadDeviceConfigurationChanged();
- void NotifyObserversKeyboardDeviceConfigurationChanged();
- void NotifyObserversMouseDeviceConfigurationChanged();
+ void NotifyObserversDeviceConfigurationChanged();
private:
InputDeviceObserverAndroid();
diff --git a/chromium/ui/events/devices/input_device_observer_win.cc b/chromium/ui/events/devices/input_device_observer_win.cc
index daa63f0b880..c8bd2039533 100644
--- a/chromium/ui/events/devices/input_device_observer_win.cc
+++ b/chromium/ui/events/devices/input_device_observer_win.cc
@@ -4,6 +4,8 @@
#include "ui/events/devices/input_device_observer_win.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/singleton.h"
@@ -12,10 +14,12 @@
#include <windows.h>
// This macro provides the implementation for the observer notification methods.
-#define NOTIFY_OBSERVERS_METHOD(method_decl, observer_call) \
- void InputDeviceObserverWin::method_decl { \
- for (InputDeviceEventObserver & observer : observers_) \
- observer.observer_call; \
+#define WIN_NOTIFY_OBSERVERS(method_decl, input_device_types) \
+ void InputDeviceObserverWin::method_decl { \
+ for (InputDeviceEventObserver & observer : observers_) { \
+ observer.OnInputDeviceConfigurationChanged( \
+ InputDeviceEventObserver::input_device_types); \
+ } \
}
namespace ui {
@@ -25,7 +29,7 @@ namespace {
// The registry subkey that contains information about the state of the
// detachable/convertible laptop, it tells if the device has an accessible
// keyboard.
-// OEMs are expected to follow this guidelines to report docked/undocked state
+// OEMs are expected to follow these guidelines to report docked/undocked state
// https://msdn.microsoft.com/en-us/windows/hardware/commercialize/customize/desktop/unattend/microsoft-windows-gpiobuttons-convertibleslatemode
const base::char16 kRegistryPriorityControl[] =
L"System\\CurrentControlSet\\Control\\PriorityControl";
@@ -42,9 +46,9 @@ InputDeviceObserverWin::InputDeviceObserverWin() : weak_factory_(this) {
slate_mode_enabled_ = IsSlateModeEnabled(registry_key_.get());
// Start watching the registry for changes.
base::win::RegKey::ChangeCallback callback =
- base::Bind(&InputDeviceObserverWin::OnRegistryKeyChanged,
- weak_factory_.GetWeakPtr(), registry_key_.get());
- registry_key_->StartWatching(callback);
+ base::BindOnce(&InputDeviceObserverWin::OnRegistryKeyChanged,
+ weak_factory_.GetWeakPtr(), registry_key_.get());
+ registry_key_->StartWatching(std::move(callback));
}
}
@@ -92,10 +96,10 @@ void InputDeviceObserverWin::RemoveObserver(
observers_.RemoveObserver(observer);
}
-NOTIFY_OBSERVERS_METHOD(NotifyObserversKeyboardDeviceConfigurationChanged(),
- OnKeyboardDeviceConfigurationChanged());
+WIN_NOTIFY_OBSERVERS(NotifyObserversKeyboardDeviceConfigurationChanged(),
+ kKeyboard);
-NOTIFY_OBSERVERS_METHOD(NotifyObserversTouchpadDeviceConfigurationChanged(),
- OnTouchpadDeviceConfigurationChanged());
+WIN_NOTIFY_OBSERVERS(NotifyObserversTouchpadDeviceConfigurationChanged(),
+ kTouchpad);
} // namespace ui
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 fbf372f14c3..9b52d3ae56f 100644
--- a/chromium/ui/events/devices/x11/device_data_manager_x11.cc
+++ b/chromium/ui/events/devices/x11/device_data_manager_x11.cc
@@ -12,8 +12,8 @@
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/singleton.h"
+#include "base/stl_util.h"
#include "base/system/sys_info.h"
#include "build/build_config.h"
#include "ui/display/display.h"
@@ -102,7 +102,7 @@ constexpr const char* kCachedAtoms[] = {
};
// Make sure the sizes of enum and |kCachedAtoms| are aligned.
-static_assert(arraysize(kCachedAtoms) ==
+static_assert(base::size(kCachedAtoms) ==
ui::DeviceDataManagerX11::DT_LAST_ENTRY,
"kCachedAtoms count / enum mismatch");
@@ -635,9 +635,8 @@ int DeviceDataManagerX11::GetMappedButton(int button) {
}
void DeviceDataManagerX11::UpdateButtonMap() {
- button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(),
- button_map_,
- arraysize(button_map_));
+ button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(), button_map_,
+ base::size(button_map_));
}
void DeviceDataManagerX11::GetGestureTimes(const XEvent& xev,
diff --git a/chromium/ui/events/devices/x11/device_data_manager_x11_unittest.cc b/chromium/ui/events/devices/x11/device_data_manager_x11_unittest.cc
index 784849c4abd..96bb913a957 100644
--- a/chromium/ui/events/devices/x11/device_data_manager_x11_unittest.cc
+++ b/chromium/ui/events/devices/x11/device_data_manager_x11_unittest.cc
@@ -31,7 +31,7 @@ class TestInputDeviceObserver : public InputDeviceEventObserver {
}
// InputDeviceEventObserver implementation.
- void OnKeyboardDeviceConfigurationChanged() override {
+ void OnInputDeviceConfigurationChanged(uint8_t) override {
change_notified_ = true;
}
diff --git a/chromium/ui/events/event.cc b/chromium/ui/events/event.cc
index 2c636ab6b42..c92b49e405a 100644
--- a/chromium/ui/events/event.cc
+++ b/chromium/ui/events/event.cc
@@ -902,10 +902,12 @@ KeyEvent::KeyEvent(EventType type,
DomCode code,
int flags,
DomKey key,
- base::TimeTicks time_stamp)
+ base::TimeTicks time_stamp,
+ bool is_char)
: Event(type, time_stamp, flags),
key_code_(key_code),
code_(code),
+ is_char_(is_char),
key_(key) {}
KeyEvent::KeyEvent(base::char16 character,
diff --git a/chromium/ui/events/event.h b/chromium/ui/events/event.h
index 1ba9510dd41..e95c40b6cc4 100644
--- a/chromium/ui/events/event.h
+++ b/chromium/ui/events/event.h
@@ -830,7 +830,8 @@ class EVENTS_EXPORT KeyEvent : public Event {
DomCode code,
int flags,
DomKey key,
- base::TimeTicks time_stamp);
+ base::TimeTicks time_stamp,
+ bool is_char = false);
// Create a character event.
KeyEvent(base::char16 character,
diff --git a/chromium/ui/events/event_constants.h b/chromium/ui/events/event_constants.h
index 3d81edebdf5..cab62faf90c 100644
--- a/chromium/ui/events/event_constants.h
+++ b/chromium/ui/events/event_constants.h
@@ -118,14 +118,17 @@ enum EventFlags {
};
// Flags specific to key events.
+// WARNING: If you add or remove values make sure traits for serializing these
+// values are updated.
enum KeyEventFlags {
EF_IME_FABRICATED_KEY = 1 << 15, // Key event fabricated by the underlying
// IME without a user action.
// (Linux X11 only)
- EF_IS_REPEAT = 1 << 16,
- EF_FINAL = 1 << 17, // Do not remap; the event was created with
- // the desired final values.
- EF_IS_EXTENDED_KEY = 1 << 18, // Windows extended key (see WM_KEYDOWN doc)
+ EF_IS_REPEAT = 1 << 16,
+ EF_FINAL = 1 << 17, // Do not remap; the event was created with
+ // the desired final values.
+ EF_IS_EXTENDED_KEY = 1 << 18, // Windows extended key (see WM_KEYDOWN doc)
+ EF_MAX_KEY_EVENT_FLAGS_VALUE = (1 << 19) - 1,
};
// Flags specific to mouse events.
diff --git a/chromium/ui/events/event_dispatcher.h b/chromium/ui/events/event_dispatcher.h
index bc9cd5b8a9c..f3fd2e3e59d 100644
--- a/chromium/ui/events/event_dispatcher.h
+++ b/chromium/ui/events/event_dispatcher.h
@@ -18,11 +18,11 @@ class EventDispatcher;
class EventTarget;
struct EventDispatchDetails {
- EventDispatchDetails()
- : dispatcher_destroyed(false),
- target_destroyed(false) {}
- bool dispatcher_destroyed;
- bool target_destroyed;
+ bool dispatcher_destroyed = false;
+ bool target_destroyed = false;
+
+ // Set to true if an EventRewriter discards the event.
+ bool event_discarded = false;
};
class EVENTS_EXPORT EventDispatcherDelegate {
diff --git a/chromium/ui/events/event_processor_unittest.cc b/chromium/ui/events/event_processor_unittest.cc
index 1c51a24e662..db597f93dc2 100644
--- a/chromium/ui/events/event_processor_unittest.cc
+++ b/chromium/ui/events/event_processor_unittest.cc
@@ -5,8 +5,8 @@
#include <utility>
#include <vector>
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/event_target_iterator.h"
@@ -403,8 +403,8 @@ TEST_F(EventProcessorTest, HandlerSequence) {
std::string expected[] = { "PreR", "PreC", "PreG", "G", "PostG", "PostC",
"PostR", "PreR", "PreC", "C", "PostC", "PostR", "PreR", "R", "PostR" };
- EXPECT_EQ(std::vector<std::string>(
- expected, expected + arraysize(expected)), recorder);
+ EXPECT_EQ(std::vector<std::string>(expected, expected + base::size(expected)),
+ recorder);
root()->RemovePreTargetHandler(&pre_root);
child_r->RemovePreTargetHandler(&pre_child);
diff --git a/chromium/ui/events/event_source.cc b/chromium/ui/events/event_source.cc
index d2c955ce6fe..85a6f402bbf 100644
--- a/chromium/ui/events/event_source.cc
+++ b/chromium/ui/events/event_source.cc
@@ -43,6 +43,12 @@ EventDispatchDetails EventSource::SendEventToSink(Event* event) {
return SendEventToSinkFromRewriter(event, nullptr);
}
+EventDispatchDetails EventSource::DeliverEventToSink(Event* event) {
+ EventSink* sink = GetEventSink();
+ CHECK(sink);
+ return sink->OnEventFromSource(event);
+}
+
EventDispatchDetails EventSource::SendEventToSinkFromRewriter(
Event* event,
const EventRewriter* rewriter) {
@@ -71,7 +77,9 @@ EventDispatchDetails EventSource::SendEventToSinkFromRewriter(
status = (*it)->RewriteEvent(*event_for_rewriting, &rewritten_event);
if (status == EVENT_REWRITE_DISCARD) {
CHECK(!rewritten_event);
- return EventDispatchDetails();
+ EventDispatchDetails details;
+ details.event_discarded = true;
+ return details;
}
if (status == EVENT_REWRITE_CONTINUE) {
CHECK(!rewritten_event);
@@ -100,10 +108,4 @@ EventDispatchDetails EventSource::SendEventToSinkFromRewriter(
return EventDispatchDetails();
}
-EventDispatchDetails EventSource::DeliverEventToSink(Event* event) {
- EventSink* sink = GetEventSink();
- CHECK(sink);
- return sink->OnEventFromSource(event);
-}
-
} // namespace ui
diff --git a/chromium/ui/events/event_source.h b/chromium/ui/events/event_source.h
index d5b9b1cc609..ad84e603eaf 100644
--- a/chromium/ui/events/event_source.h
+++ b/chromium/ui/events/event_source.h
@@ -33,10 +33,14 @@ class EVENTS_EXPORT EventSource {
void AddEventRewriter(EventRewriter* rewriter);
void RemoveEventRewriter(EventRewriter* rewriter);
- protected:
// Sends the event through all rewriters and onto the source's EventSink.
EventDispatchDetails SendEventToSink(Event* event);
+ // Send the event to the sink after rewriting; subclass overrides may queue
+ // events before delivery, i.e. for the WindowService.
+ virtual EventDispatchDetails DeliverEventToSink(Event* event);
+
+ protected:
// Sends the event through the rewriters and onto the source's EventSink.
// If |rewriter| is valid, |event| is only sent to the subsequent rewriters.
// This is used for asynchronous reposting of events processed by |rewriter|.
@@ -48,8 +52,6 @@ class EVENTS_EXPORT EventSource {
friend class EventRewriter;
friend class EventSourceTestApi;
- EventDispatchDetails DeliverEventToSink(Event* event);
-
typedef std::vector<EventRewriter*> EventRewriterList;
EventRewriterList rewriter_list_;
diff --git a/chromium/ui/events/event_unittest.cc b/chromium/ui/events/event_unittest.cc
index fee9fc13236..f0f34289048 100644
--- a/chromium/ui/events/event_unittest.cc
+++ b/chromium/ui/events/event_unittest.cc
@@ -9,7 +9,7 @@
#include <memory>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
@@ -269,7 +269,7 @@ TEST(EventTest, KeyEvent) {
{ VKEY_OEM_3, EF_SHIFT_DOWN, '~' },
};
- for (size_t i = 0; i < arraysize(kTestData); ++i) {
+ for (size_t i = 0; i < base::size(kTestData); ++i) {
KeyEvent key(ET_KEY_PRESSED,
kTestData[i].key_code,
kTestData[i].flags);
diff --git a/chromium/ui/events/keycodes/BUILD.gn b/chromium/ui/events/keycodes/BUILD.gn
index e0705f2ad12..1e6d31cc0c9 100644
--- a/chromium/ui/events/keycodes/BUILD.gn
+++ b/chromium/ui/events/keycodes/BUILD.gn
@@ -16,7 +16,7 @@ jumbo_source_set("xkb") {
deps = [
"//base",
- "//ui/base:ui_features",
+ "//ui/base:buildflags",
"//ui/events:dom_keycode_converter",
]
}
diff --git a/chromium/ui/events/keycodes/DEPS b/chromium/ui/events/keycodes/DEPS
index 162a9d72016..200ea4afa12 100644
--- a/chromium/ui/events/keycodes/DEPS
+++ b/chromium/ui/events/keycodes/DEPS
@@ -7,7 +7,7 @@ include_rules = [
"-third_party",
"-ui",
- "+ui/base/ui_features.h", # Features header doesn't bring in all of UI.
+ "+ui/base/buildflags.h", # Doesn't bring in all of UI.
"+ui/gfx/x/x11.h", # Wrapper on <X11/*>.
"+ui/gfx/x/x11_types.h", # <X11/*> replacement.
"+ui/events",
diff --git a/chromium/ui/events/keycodes/dom/dom_key.h b/chromium/ui/events/keycodes/dom/dom_key.h
index 7729f991964..3f3e7ca5931 100644
--- a/chromium/ui/events/keycodes/dom/dom_key.h
+++ b/chromium/ui/events/keycodes/dom/dom_key.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "base/logging.h"
+#include "base/optional.h"
#include "build/build_config.h"
namespace ui {
@@ -97,12 +98,20 @@ class DomKey {
DCHECK(value == 0 || IsValid()) << value;
}
+ // Factory that returns a DomKey for the specified value. Returns nullopt if
+ // |value| is not a valid value (or NONE).
+ static base::Optional<DomKey> FromBase(Base value) {
+ if (value != 0 && !IsValidValue(value))
+ return base::nullopt;
+ return Base(value);
+ }
+
// Obtain the encoded integer representation of the DomKey.
operator Base() const { return value_; }
// True if the value is a valid DomKey (which excludes DomKey::NONE and
// integers not following the DomKey format).
- bool IsValid() const { return (value_ & TYPE_MASK) != 0; }
+ bool IsValid() const { return IsValidValue(value_); }
// True if the value is a Unicode code point.
bool IsCharacter() const { return (value_ & TYPE_MASK) == TYPE_UNICODE; }
@@ -148,6 +157,8 @@ class DomKey {
};
private:
+ static bool IsValidValue(Base value) { return (value & TYPE_MASK) != 0; }
+
Base value_;
};
diff --git a/chromium/ui/events/keycodes/dom/keycode_converter.cc b/chromium/ui/events/keycodes/dom/keycode_converter.cc
index dcb997be112..df479d0e87a 100644
--- a/chromium/ui/events/keycodes/dom/keycode_converter.cc
+++ b/chromium/ui/events/keycodes/dom/keycode_converter.cc
@@ -5,7 +5,6 @@
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversion_utils.h"
#include "build/build_config.h"
@@ -34,7 +33,7 @@ namespace {
#undef USB_KEYMAP
#undef USB_KEYMAP_DECLARATION
-const size_t kKeycodeMapEntries = arraysize(usb_keycode_map);
+const size_t kKeycodeMapEntries = base::size(usb_keycode_map);
// Table of DomKey enum values and DOM Level 3 |key| strings.
struct DomKeyMapEntry {
@@ -50,7 +49,7 @@ struct DomKeyMapEntry {
#undef DOM_KEY_MAP
#undef DOM_KEY_UNI
-const size_t kDomKeyMapEntries = arraysize(dom_key_map);
+const size_t kDomKeyMapEntries = base::size(dom_key_map);
} // namespace
diff --git a/chromium/ui/events/keycodes/dom/keycode_converter_unittest.cc b/chromium/ui/events/keycodes/dom/keycode_converter_unittest.cc
index 2fa7249890a..d3e51aa3be1 100644
--- a/chromium/ui/events/keycodes/dom/keycode_converter_unittest.cc
+++ b/chromium/ui/events/keycodes/dom/keycode_converter_unittest.cc
@@ -10,6 +10,7 @@
#include <map>
#include <set>
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/keycodes/dom/dom_code.h"
@@ -29,7 +30,7 @@ const size_t expected_mapped_key_count[] = {
118, // mac
};
-const size_t kNativeColumns = arraysize(expected_mapped_key_count);
+const size_t kNativeColumns = base::size(expected_mapped_key_count);
struct KeycodeConverterData {
uint32_t usb_keycode;
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion.cc b/chromium/ui/events/keycodes/keyboard_code_conversion.cc
index c1125455245..45a6999a154 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion.cc
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion.cc
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
@@ -206,14 +206,6 @@ KeyboardCode NonLocatedToLocatedKeyboardCode(KeyboardCode key_code,
return IsRightSideDomCode(dom_code) ? VKEY_RMENU : VKEY_LMENU;
case VKEY_LWIN:
return IsRightSideDomCode(dom_code) ? VKEY_RWIN : VKEY_LWIN;
- default:
- return NonLocatedToLocatedKeypadKeyboardCode(key_code, dom_code);
- }
-}
-
-KeyboardCode NonLocatedToLocatedKeypadKeyboardCode(KeyboardCode key_code,
- DomCode dom_code) {
- switch (key_code) {
case VKEY_0:
return (dom_code == DomCode::NUMPAD0) ? VKEY_NUMPAD0 : VKEY_0;
case VKEY_1:
@@ -254,7 +246,7 @@ DomCode UsLayoutKeyboardCodeToDomCode(KeyboardCode key_code) {
KeyboardCode DomCodeToUsLayoutKeyboardCode(DomCode dom_code) {
const DomCodeToKeyboardCodeEntry* end =
- kDomCodeToKeyboardCodeMap + arraysize(kDomCodeToKeyboardCodeMap);
+ kDomCodeToKeyboardCodeMap + base::size(kDomCodeToKeyboardCodeMap);
const DomCodeToKeyboardCodeEntry* found = std::lower_bound(
kDomCodeToKeyboardCodeMap, end, dom_code,
[](const DomCodeToKeyboardCodeEntry& a, DomCode b) {
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion.h b/chromium/ui/events/keycodes/keyboard_code_conversion.h
index 2815c8df09c..d3c035cef65 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion.h
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion.h
@@ -90,11 +90,6 @@ LocatedToNonLocatedKeyboardCode(KeyboardCode key_code);
EVENTS_BASE_EXPORT KeyboardCode
NonLocatedToLocatedKeyboardCode(KeyboardCode key_code, DomCode dom_code);
-// Determine the located VKEY corresponding to a non-located VKEY for
-// keypad vkeys. (eg. VKEY_1 (with DomCode::NUMPAD1 maps to VKEY_NUMPAD1).
-EVENTS_BASE_EXPORT KeyboardCode
-NonLocatedToLocatedKeypadKeyboardCode(KeyboardCode key_code, DomCode dom_code);
-
// Returns a DOM Level 3 |code| from a Windows-based VKEY value.
// This assumes a US layout and should only be used when |code| cannot be
// determined from a physical scan code, for example when a key event was
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm b/chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm
index 873c4ce4457..d6b01cc1f50 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm
@@ -11,8 +11,8 @@
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "base/mac/scoped_cftyperef.h"
-#include "base/macros.h"
#include "base/memory/scoped_policy.h"
+#include "base/stl_util.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
namespace ui {
@@ -573,9 +573,9 @@ int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode,
from.keycode = keycode;
const KeyCodeMap* ptr = std::lower_bound(
- kKeyCodesMap, kKeyCodesMap + arraysize(kKeyCodesMap), from);
+ kKeyCodesMap, kKeyCodesMap + base::size(kKeyCodesMap), from);
- if (ptr >= kKeyCodesMap + arraysize(kKeyCodesMap) ||
+ if (ptr >= kKeyCodesMap + base::size(kKeyCodesMap) ||
ptr->keycode != keycode || ptr->macKeycode == -1)
return -1;
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc b/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
index b1e1e3f86ad..581e0b2b925 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
@@ -9,7 +9,7 @@
#include <algorithm>
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -556,7 +556,7 @@ bool IsTtyFunctionOrSpaceKey(KeySym keysym) {
XK_space
};
- for (size_t i = 0; i < arraysize(keysyms); ++i) {
+ for (size_t i = 0; i < base::size(keysyms); ++i) {
if (keysyms[i] == keysym)
return true;
}
@@ -620,12 +620,12 @@ KeyboardCode KeyboardCodeFromXKeyEvent(const XEvent* xev) {
!IsCursorKey(keysym) && !IsPFKey(keysym) && !IsFunctionKey(keysym) &&
!IsModifierKey(keysym)) {
MAP0 key0 = {keysym & 0xFFFF, 0};
- keycode = FindVK(key0, map0, arraysize(map0));
+ keycode = FindVK(key0, map0, base::size(map0));
if (keycode != VKEY_UNKNOWN)
return keycode;
MAP1 key1 = {keysym & 0xFFFF, xkey->keycode, 0};
- keycode = FindVK(key1, map1, arraysize(map1));
+ keycode = FindVK(key1, map1, base::size(map1));
if (keycode != VKEY_UNKNOWN)
return keycode;
@@ -633,7 +633,7 @@ KeyboardCode KeyboardCodeFromXKeyEvent(const XEvent* xev) {
xkey->state |= ShiftMask;
XLookupString(xkey, NULL, 0, &keysym_shift, NULL);
MAP2 key2 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF, 0};
- keycode = FindVK(key2, map2, arraysize(map2));
+ keycode = FindVK(key2, map2, base::size(map2));
if (keycode != VKEY_UNKNOWN)
return keycode;
@@ -643,7 +643,7 @@ KeyboardCode KeyboardCodeFromXKeyEvent(const XEvent* xev) {
XLookupString(xkey, NULL, 0, &keysym_altgr, NULL);
MAP3 key3 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF,
keysym_altgr & 0xFFFF, 0};
- keycode = FindVK(key3, map3, arraysize(map3));
+ keycode = FindVK(key3, map3, base::size(map3));
if (keycode != VKEY_UNKNOWN)
return keycode;
@@ -653,9 +653,9 @@ KeyboardCode KeyboardCodeFromXKeyEvent(const XEvent* xev) {
MAP3 key4 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF, 0,
0};
const MAP3* p =
- std::lower_bound(map3, map3 + arraysize(map3), key4, MAP3());
- if (p != map3 + arraysize(map3) && p->ch0 == key4.ch0 && p->sc == key4.sc &&
- p->ch1 == key4.ch1)
+ std::lower_bound(map3, map3 + base::size(map3), key4, MAP3());
+ if (p != map3 + base::size(map3) && p->ch0 == key4.ch0 &&
+ p->sc == key4.sc && p->ch1 == key4.ch1)
return static_cast<KeyboardCode>(p->vk);
}
@@ -1150,7 +1150,7 @@ KeyboardCode DefaultKeyboardCodeFromHardwareKeycode(
VKEY_COMPOSE, // 0x87: KEY_COMPOSE Menu
};
- if (hardware_code >= arraysize(kHardwareKeycodeMap)) {
+ if (hardware_code >= base::size(kHardwareKeycodeMap)) {
// Additional keycodes used by the Chrome OS top row special function keys.
switch (hardware_code) {
case 0xA6: // KEY_BACK
diff --git a/chromium/ui/events/keycodes/keysym_to_unicode.cc b/chromium/ui/events/keycodes/keysym_to_unicode.cc
index 9413e97d59b..804afa1594c 100644
--- a/chromium/ui/events/keycodes/keysym_to_unicode.cc
+++ b/chromium/ui/events/keycodes/keysym_to_unicode.cc
@@ -6,9 +6,8 @@
#include <stddef.h>
-#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "ui/gfx/x/x11.h"
namespace ui {
@@ -812,8 +811,8 @@ const struct {
class KeySymToUnicode {
public:
KeySymToUnicode()
- : keysym_to_unicode_map_(arraysize(g_keysym_to_unicode_table)) {
- for (size_t i = 0; i < arraysize(g_keysym_to_unicode_table); ++i) {
+ : keysym_to_unicode_map_(base::size(g_keysym_to_unicode_table)) {
+ for (size_t i = 0; i < base::size(g_keysym_to_unicode_table); ++i) {
keysym_to_unicode_map_[g_keysym_to_unicode_table[i].keysym] =
g_keysym_to_unicode_table[i].unicode;
}
@@ -839,7 +838,7 @@ class KeySymToUnicode {
}
private:
- typedef base::hash_map<KeySym, uint16_t> KeySymToUnicodeMap;
+ typedef std::unordered_map<KeySym, uint16_t> KeySymToUnicodeMap;
KeySymToUnicodeMap keysym_to_unicode_map_;
DISALLOW_COPY_AND_ASSIGN(KeySymToUnicode);
diff --git a/chromium/ui/events/keycodes/platform_key_map_win.cc b/chromium/ui/events/keycodes/platform_key_map_win.cc
index c803dc47130..3382d350de9 100644
--- a/chromium/ui/events/keycodes/platform_key_map_win.cc
+++ b/chromium/ui/events/keycodes/platform_key_map_win.cc
@@ -10,8 +10,9 @@
#include "base/feature_list.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/macros.h"
-#include "base/threading/thread_local_storage.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "base/threading/thread_local.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_utils.h"
@@ -71,11 +72,11 @@ int ReplaceAltGraphWithControlAndAlt(int flags) {
: flags;
}
-const int kModifierFlagsCombinations = (1 << arraysize(modifier_flags)) - 1;
+const int kModifierFlagsCombinations = (1 << base::size(modifier_flags)) - 1;
int GetModifierFlags(int combination) {
int flags = EF_NONE;
- for (size_t i = 0; i < arraysize(modifier_flags); ++i) {
+ for (size_t i = 0; i < base::size(modifier_flags); ++i) {
if (combination & (1 << i))
flags |= modifier_flags[i];
}
@@ -258,26 +259,6 @@ DomKey NonPrintableKeyboardCodeToDomKey(KeyboardCode key_code, HKL layout) {
return DomKey::NONE;
}
-void CleanupKeyMapTls(void* data) {
- PlatformKeyMap* key_map = reinterpret_cast<PlatformKeyMap*>(data);
- delete key_map;
-}
-
-struct PlatformKeyMapInstanceTlsTraits
- : public base::internal::DestructorAtExitLazyInstanceTraits<
- base::ThreadLocalStorage::Slot> {
- static base::ThreadLocalStorage::Slot* New(void* instance) {
- // Use placement new to initialize our instance in our preallocated space.
- // TODO(input-dev): Use std::default_delete instead of providing own
- // function.
- return new (instance) base::ThreadLocalStorage::Slot(CleanupKeyMapTls);
- }
-};
-
-base::LazyInstance<base::ThreadLocalStorage::Slot,
- PlatformKeyMapInstanceTlsTraits>
- g_platform_key_map_tls_lazy = LAZY_INSTANCE_INITIALIZER;
-
} // anonymous namespace
PlatformKeyMap::PlatformKeyMap() {}
@@ -288,6 +269,25 @@ PlatformKeyMap::PlatformKeyMap(HKL layout) {
PlatformKeyMap::~PlatformKeyMap() {}
+// static
+PlatformKeyMap* PlatformKeyMap::GetThreadLocalPlatformKeyMap() {
+ // DestructorAtExit so the main thread's instance is cleaned up between tests
+ // in the same process.
+ static base::LazyInstance<base::ThreadLocalOwnedPointer<PlatformKeyMap>>::
+ DestructorAtExit platform_key_map_tls_instance =
+ LAZY_INSTANCE_INITIALIZER;
+
+ auto& platform_key_map_tls = platform_key_map_tls_instance.Get();
+ PlatformKeyMap* platform_key_map = platform_key_map_tls.Get();
+ if (!platform_key_map) {
+ auto new_platform_key_map = base::WrapUnique(new PlatformKeyMap);
+ platform_key_map = new_platform_key_map.get();
+ platform_key_map_tls.Set(std::move(new_platform_key_map));
+ }
+
+ return platform_key_map;
+}
+
DomKey PlatformKeyMap::DomKeyFromKeyboardCodeImpl(KeyboardCode key_code,
int* flags) const {
// Windows expresses right-Alt as VKEY_MENU with the extended flag set.
@@ -338,14 +338,7 @@ DomKey PlatformKeyMap::DomKeyFromKeyboardCode(KeyboardCode key_code,
// Use TLS because KeyboardLayout is per thread.
// However currently PlatformKeyMap will only be used by the host application,
// which is just one process and one thread.
- base::ThreadLocalStorage::Slot* platform_key_map_tls =
- g_platform_key_map_tls_lazy.Pointer();
- PlatformKeyMap* platform_key_map =
- reinterpret_cast<PlatformKeyMap*>(platform_key_map_tls->Get());
- if (!platform_key_map) {
- platform_key_map = new PlatformKeyMap();
- platform_key_map_tls->Set(platform_key_map);
- }
+ PlatformKeyMap* platform_key_map = GetThreadLocalPlatformKeyMap();
HKL current_layout = ::GetKeyboardLayout(0);
platform_key_map->UpdateLayout(current_layout);
@@ -361,14 +354,7 @@ int PlatformKeyMap::ReplaceControlAndAltWithAltGraph(int flags) {
// static
bool PlatformKeyMap::UsesAltGraph() {
- base::ThreadLocalStorage::Slot* platform_key_map_tls =
- g_platform_key_map_tls_lazy.Pointer();
- PlatformKeyMap* platform_key_map =
- reinterpret_cast<PlatformKeyMap*>(platform_key_map_tls->Get());
- if (!platform_key_map) {
- platform_key_map = new PlatformKeyMap();
- platform_key_map_tls->Set(platform_key_map);
- }
+ PlatformKeyMap* platform_key_map = GetThreadLocalPlatformKeyMap();
HKL current_layout = ::GetKeyboardLayout(0);
platform_key_map->UpdateLayout(current_layout);
@@ -405,14 +391,14 @@ void PlatformKeyMap::UpdateLayout(HKL layout) {
for (int key_code = 0; key_code <= 0xFF; ++key_code) {
wchar_t translated_chars[5];
int rv = ::ToUnicodeEx(key_code, 0, keyboard_state, translated_chars,
- arraysize(translated_chars), 0, keyboard_layout_);
+ base::size(translated_chars), 0, keyboard_layout_);
if (rv == -1) {
// Dead key, injecting VK_SPACE to get character representation.
BYTE empty_state[256];
memset(empty_state, 0, sizeof(empty_state));
rv = ::ToUnicodeEx(VK_SPACE, 0, empty_state, translated_chars,
- arraysize(translated_chars), 0, keyboard_layout_);
+ base::size(translated_chars), 0, keyboard_layout_);
// Expecting a dead key character (not followed by a space).
if (rv == 1) {
printable_keycode_to_key_[std::make_pair(static_cast<int>(key_code),
diff --git a/chromium/ui/events/keycodes/platform_key_map_win.h b/chromium/ui/events/keycodes/platform_key_map_win.h
index 2a8dc38b720..fe884c24140 100644
--- a/chromium/ui/events/keycodes/platform_key_map_win.h
+++ b/chromium/ui/events/keycodes/platform_key_map_win.h
@@ -44,6 +44,9 @@ class EVENTS_EXPORT PlatformKeyMap {
PlatformKeyMap();
+ // Returns the PlatformKeyMap instance for the current thread.
+ static PlatformKeyMap* GetThreadLocalPlatformKeyMap();
+
// TODO(input-dev): Expose this function when we need to access separate
// layout. Returns the DomKey 'meaning' of |KeyboardCode| in the context of
// specified |EventFlags| and stored keyboard layout.
diff --git a/chromium/ui/events/keycodes/xkb_keysym.h b/chromium/ui/events/keycodes/xkb_keysym.h
index e2cbf6ade5d..88e83c5e62c 100644
--- a/chromium/ui/events/keycodes/xkb_keysym.h
+++ b/chromium/ui/events/keycodes/xkb_keysym.h
@@ -5,7 +5,7 @@
#ifndef UI_EVENTS_KEYCODES_XKB_KEYSYM_H_
#define UI_EVENTS_KEYCODES_XKB_KEYSYM_H_
-#include "ui/base/ui_features.h"
+#include "ui/base/buildflags.h"
// This file provides definitions of the xkbcommon keysym type (xkb_keysym_t)
// and values (XKB_KEY_...) for both xkbcommon and traditional X11.
diff --git a/chromium/ui/events/mojo/event.mojom b/chromium/ui/events/mojo/event.mojom
index b8364e07f79..944f16c0181 100644
--- a/chromium/ui/events/mojo/event.mojom
+++ b/chromium/ui/events/mojo/event.mojom
@@ -10,43 +10,19 @@ import "ui/events/mojo/keyboard_codes.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/latency/mojo/latency_info.mojom";
+// The values here correspond to the values defined in ui::KeyEvent.
struct KeyData {
- // The chromium event key code; these values are from the ui/ KeyCode enum,
- // which has the fun property of being neither consistently the Windows key
- // code, nor the X11 keycodes. (This value is consistent across platforms
- // for basic ASCII characters; it will differ for modifiers. We don't define
- // this as a mojo enum because mojom doesn't appear to have a platform
- // dependent preprocessor yet.)
- //
- // TODO(erg): Remove this, and declare Win32 keycodes correct by fiat. We can
- // not do this until we remove ui::Event usage from within mojo.
+ // The VKEY value of the key.
int32 key_code;
- // Whether this is a character event, and the character value if it is. Note
- // that this is different than |text|, which holds a value even when there
- // isn't actually a character to insert. (For example, |text| will be set and
- // have a value on backspace, and |character| won't.)
+ // The ui::DomCode value.
+ uint32 dom_code;
+
+ // The ui::DomKey value.
+ int32 dom_key;
+
+ // True if this is a character event, false if this is a keystroke event.
bool is_char;
- uint16 character;
-
- // The Win32 key code. Because of the web, this is the closest thing that we
- // have to a cross platform key state.
- KeyboardCode windows_key_code;
-
- // The platform specific key code.
- //
- // TODO(erg): This exists only for NPAPI support, pepper USB keyboard support
- // and IME on android support. Theoretically, we should be able to remove this
- // in the medium to long term.
- int32 native_key_code;
-
- // The text generated by this keystroke. Corresponds to
- // blink::WebKeyboardEvent::text.
- uint16 text;
-
- // Like |text|, but unmodified by concurrently held modifier keys (except
- // shift). Corresponds to blink::WebKeyboardEvent::unmodifiedText.
- uint16 unmodified_text;
};
struct LocationData {
@@ -60,6 +36,9 @@ struct LocationData {
// TODO(crbug.com/767087): Expand GestureEvent and GestureEventDetails support.
struct GestureData {
LocationData location;
+ GestureDeviceType device_type;
+ // The scale of pinch update events.
+ float scale;
};
// Data to support scroll events.
diff --git a/chromium/ui/events/mojo/event.typemap b/chromium/ui/events/mojo/event.typemap
index a652049bb12..74b8864cf8a 100644
--- a/chromium/ui/events/mojo/event.typemap
+++ b/chromium/ui/events/mojo/event.typemap
@@ -25,4 +25,5 @@ type_mappings = [
"ui.mojom.EventMomentumPhase=ui::EventMomentumPhase",
"ui.mojom.PointerDetails=ui::PointerDetails",
"ui.mojom.ScrollEventPhase=ui::ScrollEventPhase",
+ "ui.mojom.GestureDeviceType=ui::GestureDeviceType",
]
diff --git a/chromium/ui/events/mojo/event_constants.mojom b/chromium/ui/events/mojo/event_constants.mojom
index fd0356c6fc2..103d9b34be2 100644
--- a/chromium/ui/events/mojo/event_constants.mojom
+++ b/chromium/ui/events/mojo/event_constants.mojom
@@ -17,6 +17,10 @@ enum EventType {
KEY_PRESSED,
KEY_RELEASED,
GESTURE_TAP,
+ GESTURE_SWIPE,
+ GESTURE_PINCH_BEGIN,
+ GESTURE_PINCH_END,
+ GESTURE_PINCH_UPDATE,
SCROLL,
SCROLL_FLING_START,
SCROLL_FLING_CANCEL,
@@ -89,4 +93,12 @@ enum EventMomentumPhase {
MAY_BEGIN,
INERTIAL_UPDATE,
END,
-}; \ No newline at end of file
+};
+
+// Device type for gesture events.
+// These values match ui::GestureDeviceType in ui/events/event_constants.h
+enum GestureDeviceType {
+ DEVICE_UNKNOWN,
+ DEVICE_TOUCHPAD,
+ DEVICE_TOUCHSCREEN,
+};
diff --git a/chromium/ui/events/mojo/event_struct_traits.cc b/chromium/ui/events/mojo/event_struct_traits.cc
index ca6e276e4e1..a624bac5fd3 100644
--- a/chromium/ui/events/mojo/event_struct_traits.cc
+++ b/chromium/ui/events/mojo/event_struct_traits.cc
@@ -48,10 +48,15 @@ bool ReadGestureData(ui::mojom::EventDataView* event,
if (!event->ReadGestureData<ui::mojom::GestureDataPtr>(&gesture_data))
return false;
+ ui::GestureEventDetails details(ConvertTo<ui::EventType>(event->action()));
+ details.set_device_type(gesture_data->device_type);
+ if (details.type() == ui::ET_GESTURE_PINCH_UPDATE)
+ details.set_scale(gesture_data->scale);
+
*out = std::make_unique<ui::GestureEvent>(
gesture_data->location->relative_location.x(),
gesture_data->location->relative_location.y(), event->flags(), time_stamp,
- ui::GestureEventDetails(ConvertTo<ui::EventType>(event->action())));
+ details);
return true;
}
@@ -117,6 +122,14 @@ ui::mojom::EventType TypeConverter<ui::mojom::EventType,
return ui::mojom::EventType::KEY_RELEASED;
case ui::ET_GESTURE_TAP:
return ui::mojom::EventType::GESTURE_TAP;
+ case ui::ET_GESTURE_SWIPE:
+ return ui::mojom::EventType::GESTURE_SWIPE;
+ case ui::ET_GESTURE_PINCH_BEGIN:
+ return ui::mojom::EventType::GESTURE_PINCH_BEGIN;
+ case ui::ET_GESTURE_PINCH_END:
+ return ui::mojom::EventType::GESTURE_PINCH_END;
+ case ui::ET_GESTURE_PINCH_UPDATE:
+ return ui::mojom::EventType::GESTURE_PINCH_UPDATE;
case ui::ET_SCROLL:
return ui::mojom::EventType::SCROLL;
case ui::ET_SCROLL_FLING_START:
@@ -169,6 +182,14 @@ ui::EventType TypeConverter<ui::EventType, ui::mojom::EventType>::Convert(
return ui::ET_KEY_RELEASED;
case ui::mojom::EventType::GESTURE_TAP:
return ui::ET_GESTURE_TAP;
+ case ui::mojom::EventType::GESTURE_SWIPE:
+ return ui::ET_GESTURE_SWIPE;
+ case ui::mojom::EventType::GESTURE_PINCH_BEGIN:
+ return ui::ET_GESTURE_PINCH_BEGIN;
+ case ui::mojom::EventType::GESTURE_PINCH_END:
+ return ui::ET_GESTURE_PINCH_END;
+ case ui::mojom::EventType::GESTURE_PINCH_UPDATE:
+ return ui::ET_GESTURE_PINCH_UPDATE;
case ui::mojom::EventType::SCROLL:
return ui::ET_SCROLL;
case ui::mojom::EventType::SCROLL_FLING_START:
@@ -241,15 +262,11 @@ StructTraits<ui::mojom::EventDataView, EventUniquePtr>::key_data(
const ui::KeyEvent* key_event = event->AsKeyEvent();
ui::mojom::KeyDataPtr key_data(ui::mojom::KeyData::New());
- key_data->key_code = key_event->GetConflatedWindowsKeyCode();
- key_data->native_key_code =
- ui::KeycodeConverter::DomCodeToNativeKeycode(key_event->code());
+
+ key_data->key_code = static_cast<int32_t>(key_event->key_code());
key_data->is_char = key_event->is_char();
- key_data->character = key_event->GetCharacter();
- key_data->windows_key_code = static_cast<ui::mojom::KeyboardCode>(
- key_event->GetLocatedWindowsKeyboardCode());
- key_data->text = key_event->GetText();
- key_data->unmodified_text = key_event->GetUnmodifiedText();
+ key_data->dom_code = static_cast<uint32_t>(key_event->code());
+ key_data->dom_key = static_cast<int32_t>(key_event->GetDomKey());
return key_data;
}
@@ -277,8 +294,13 @@ StructTraits<ui::mojom::EventDataView, EventUniquePtr>::gesture_data(
if (!event->IsGestureEvent())
return nullptr;
+ const ui::GestureEvent* gesture_event = event->AsGestureEvent();
ui::mojom::GestureDataPtr gesture_data(ui::mojom::GestureData::New());
- gesture_data->location = CreateLocationData(event->AsLocatedEvent());
+ gesture_data->location = CreateLocationData(gesture_event);
+ gesture_data->device_type = gesture_event->details().device_type();
+ gesture_data->scale = (event->type() == ui::ET_GESTURE_PINCH_UPDATE)
+ ? gesture_event->details().scale()
+ : 1.f;
return gesture_data;
}
@@ -341,22 +363,39 @@ bool StructTraits<ui::mojom::EventDataView, EventUniquePtr>::Read(
if (!event.ReadKeyData<ui::mojom::KeyDataPtr>(&key_data))
return false;
- if (key_data->is_char) {
- *out = std::make_unique<ui::KeyEvent>(
- static_cast<base::char16>(key_data->character),
- static_cast<ui::KeyboardCode>(key_data->key_code),
- ui::DomCode::NONE, event.flags(), time_stamp);
- } else {
- *out = std::make_unique<ui::KeyEvent>(
- event.action() == ui::mojom::EventType::KEY_PRESSED
- ? ui::ET_KEY_PRESSED
- : ui::ET_KEY_RELEASED,
- static_cast<ui::KeyboardCode>(key_data->key_code), event.flags(),
- time_stamp);
+ base::Optional<ui::DomKey> dom_key =
+ ui::DomKey::FromBase(key_data->dom_key);
+ if (!dom_key)
+ return false;
+
+ if (!key_data->is_char &&
+ (key_data->key_code < 0 || key_data->key_code > 255)) {
+ return false;
}
+ if (event.flags() > ui::EF_MAX_KEY_EVENT_FLAGS_VALUE)
+ return false;
+
+ const ui::KeyboardCode key_code =
+ static_cast<ui::KeyboardCode>(key_data->key_code);
+ // Deserialization uses UsbKeycodeToDomCode() rather than a direct cast
+ // to ensure the value is valid. Invalid values are mapped to
+ // DomCode::NONE.
+ const ui::DomCode dom_code =
+ ui::KeycodeConverter::UsbKeycodeToDomCode(key_data->dom_code);
+ const ui::EventType event_type =
+ (event.action() == ui::mojom::EventType::KEY_PRESSED)
+ ? ui::ET_KEY_PRESSED
+ : ui::ET_KEY_RELEASED;
+ *out = std::make_unique<ui::KeyEvent>(event_type, key_code, dom_code,
+ event.flags(), *dom_key, time_stamp,
+ key_data->is_char);
break;
}
case ui::mojom::EventType::GESTURE_TAP:
+ case ui::mojom::EventType::GESTURE_SWIPE:
+ case ui::mojom::EventType::GESTURE_PINCH_BEGIN:
+ case ui::mojom::EventType::GESTURE_PINCH_END:
+ case ui::mojom::EventType::GESTURE_PINCH_UPDATE:
if (!ReadGestureData(&event, time_stamp, out))
return false;
break;
diff --git a/chromium/ui/events/mojo/event_struct_traits.h b/chromium/ui/events/mojo/event_struct_traits.h
index 113b5e04e8b..92ac1b3fbde 100644
--- a/chromium/ui/events/mojo/event_struct_traits.h
+++ b/chromium/ui/events/mojo/event_struct_traits.h
@@ -197,6 +197,39 @@ struct EnumTraits<ui::mojom::ScrollEventPhase, ui::ScrollEventPhase> {
}
};
+template <>
+struct EnumTraits<ui::mojom::GestureDeviceType, ui::GestureDeviceType> {
+ static ui::mojom::GestureDeviceType ToMojom(ui::GestureDeviceType input) {
+ switch (input) {
+ case ui::GestureDeviceType::DEVICE_UNKNOWN:
+ return ui::mojom::GestureDeviceType::DEVICE_UNKNOWN;
+ case ui::GestureDeviceType::DEVICE_TOUCHPAD:
+ return ui::mojom::GestureDeviceType::DEVICE_TOUCHPAD;
+ case ui::GestureDeviceType::DEVICE_TOUCHSCREEN:
+ return ui::mojom::GestureDeviceType::DEVICE_TOUCHSCREEN;
+ }
+ NOTREACHED();
+ return ui::mojom::GestureDeviceType::DEVICE_UNKNOWN;
+ }
+
+ static bool FromMojom(ui::mojom::GestureDeviceType input,
+ ui::GestureDeviceType* out) {
+ switch (input) {
+ case ui::mojom::GestureDeviceType::DEVICE_UNKNOWN:
+ *out = ui::GestureDeviceType::DEVICE_UNKNOWN;
+ return true;
+ case ui::mojom::GestureDeviceType::DEVICE_TOUCHPAD:
+ *out = ui::GestureDeviceType::DEVICE_TOUCHPAD;
+ return true;
+ case ui::mojom::GestureDeviceType::DEVICE_TOUCHSCREEN:
+ *out = ui::GestureDeviceType::DEVICE_TOUCHSCREEN;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+ }
+};
+
} // namespace mojo
#endif // UI_EVENTS_MOJO_EVENT_STRUCT_TRAITS_H_
diff --git a/chromium/ui/events/mojo/struct_traits_unittest.cc b/chromium/ui/events/mojo/struct_traits_unittest.cc
index d85050bfdf4..004a3b0a239 100644
--- a/chromium/ui/events/mojo/struct_traits_unittest.cc
+++ b/chromium/ui/events/mojo/struct_traits_unittest.cc
@@ -15,6 +15,11 @@
#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
#include "ui/latency/mojo/latency_info_struct_traits.h"
+#if defined(USE_OZONE)
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" // nogncheck
+#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h" // nogncheck
+#endif
+
namespace ui {
namespace {
@@ -43,6 +48,17 @@ void ExpectMouseWheelEventsEqual(const MouseWheelEvent& expected,
EXPECT_EQ(expected.offset(), actual.offset());
}
+void ExpectKeyEventsEqual(const KeyEvent& expected, const KeyEvent& actual) {
+ EXPECT_EQ(expected.GetCharacter(), actual.GetCharacter());
+ EXPECT_EQ(expected.GetUnmodifiedText(), actual.GetUnmodifiedText());
+ EXPECT_EQ(expected.GetText(), actual.GetText());
+ EXPECT_EQ(expected.is_char(), actual.is_char());
+ EXPECT_EQ(expected.is_repeat(), actual.is_repeat());
+ EXPECT_EQ(expected.GetConflatedWindowsKeyCode(),
+ actual.GetConflatedWindowsKeyCode());
+ EXPECT_EQ(expected.code(), actual.code());
+}
+
void ExpectEventsEqual(const Event& expected, const Event& actual) {
EXPECT_EQ(expected.type(), actual.type());
EXPECT_EQ(expected.time_stamp(), actual.time_stamp());
@@ -65,6 +81,10 @@ void ExpectEventsEqual(const Event& expected, const Event& actual) {
ASSERT_TRUE(actual.IsTouchEvent());
ExpectTouchEventsEqual(*expected.AsTouchEvent(), *actual.AsTouchEvent());
}
+ if (expected.IsKeyEvent()) {
+ ASSERT_TRUE(actual.IsKeyEvent());
+ ExpectKeyEventsEqual(*expected.AsKeyEvent(), *actual.AsKeyEvent());
+ }
}
} // namespace
@@ -95,15 +115,6 @@ TEST(StructTraitsTest, KeyEvent) {
const KeyEvent* output_key_event = output->AsKeyEvent();
ExpectEventsEqual(kTestData[i], *output_key_event);
- EXPECT_EQ(kTestData[i].GetCharacter(), output_key_event->GetCharacter());
- EXPECT_EQ(kTestData[i].GetUnmodifiedText(),
- output_key_event->GetUnmodifiedText());
- EXPECT_EQ(kTestData[i].GetText(), output_key_event->GetText());
- EXPECT_EQ(kTestData[i].is_char(), output_key_event->is_char());
- EXPECT_EQ(kTestData[i].is_repeat(), output_key_event->is_repeat());
- EXPECT_EQ(kTestData[i].GetConflatedWindowsKeyCode(),
- output_key_event->GetConflatedWindowsKeyCode());
- EXPECT_EQ(kTestData[i].code(), output_key_event->code());
}
}
@@ -219,6 +230,14 @@ TEST(StructTraitsTest, KeyEventPropertiesSerialized) {
}
TEST(StructTraitsTest, GestureEvent) {
+ GestureEventDetails pinch_begin_details(ET_GESTURE_PINCH_BEGIN);
+ pinch_begin_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+ GestureEventDetails pinch_end_details(ET_GESTURE_PINCH_END);
+ pinch_end_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+ GestureEventDetails pinch_update_details(ET_GESTURE_PINCH_UPDATE);
+ pinch_update_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+ pinch_update_details.set_scale(1.23f);
+
const GestureEvent kTestData[] = {
{10, 20, EF_NONE,
base::TimeTicks() + base::TimeDelta::FromMicroseconds(401),
@@ -226,6 +245,15 @@ TEST(StructTraitsTest, GestureEvent) {
{10, 20, EF_NONE,
base::TimeTicks() + base::TimeDelta::FromMicroseconds(401),
GestureEventDetails(ET_GESTURE_TAP)},
+ {10, 20, EF_NONE,
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(401),
+ pinch_begin_details},
+ {10, 20, EF_NONE,
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(401),
+ pinch_end_details},
+ {10, 20, EF_NONE,
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(401),
+ pinch_update_details},
};
for (size_t i = 0; i < base::size(kTestData); i++) {
@@ -371,4 +399,44 @@ TEST(StructTraitsTest, UnserializedTouchEventFields) {
output->AsTouchEvent()->unique_event_id());
}
+#if defined(USE_OZONE)
+
+// Test KeyboardLayoutEngine implementation that always returns 'x'.
+class FixedKeyboardLayoutEngine : public StubKeyboardLayoutEngine {
+ public:
+ FixedKeyboardLayoutEngine() = default;
+ ~FixedKeyboardLayoutEngine() override = default;
+
+ // StubKeyboardLayoutEngine:
+ bool Lookup(DomCode dom_code,
+ int flags,
+ DomKey* out_dom_key,
+ KeyboardCode* out_key_code) const override {
+ *out_dom_key = DomKey::FromCharacter('x');
+ *out_key_code = ui::VKEY_X;
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FixedKeyboardLayoutEngine);
+};
+
+TEST(StructTraitsTest, DifferentKeyboardLayout) {
+ // Verifies KeyEvent serialization is not impacted by a KeyboardLayoutEngine.
+ KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
+ std::make_unique<FixedKeyboardLayoutEngine>());
+ std::unique_ptr<KeyEvent> key_event = std::make_unique<KeyEvent>(
+ ET_KEY_PRESSED, VKEY_S, DomCode::US_S, EF_NONE,
+ DomKey::FromCharacter('s'), base::TimeTicks::Now());
+ std::unique_ptr<Event> expected = std::move(key_event);
+ std::unique_ptr<Event> output;
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::Event>(&expected, &output));
+ ExpectEventsEqual(*expected, *output);
+ KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
+ std::make_unique<StubKeyboardLayoutEngine>());
+}
+
+#endif
+
} // namespace ui
diff --git a/chromium/ui/events/ozone/device/udev/device_manager_udev.cc b/chromium/ui/events/ozone/device/udev/device_manager_udev.cc
index 52ac57ce60d..895a4d48b92 100644
--- a/chromium/ui/events/ozone/device/udev/device_manager_udev.cc
+++ b/chromium/ui/events/ozone/device/udev/device_manager_udev.cc
@@ -6,8 +6,8 @@
#include <stddef.h>
-#include "base/macros.h"
#include "base/message_loop/message_loop_current.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "ui/events/ozone/device/device_event.h"
@@ -66,7 +66,7 @@ device::ScopedUdevMonitorPtr UdevCreateMonitor(struct udev* udev) {
struct udev_monitor* monitor =
device::udev_monitor_new_from_netlink(udev, "udev");
if (monitor) {
- for (size_t i = 0; i < arraysize(kSubsystems); ++i)
+ for (size_t i = 0; i < base::size(kSubsystems); ++i)
device::udev_monitor_filter_add_match_subsystem_devtype(
monitor, kSubsystems[i], NULL);
@@ -107,7 +107,7 @@ void DeviceManagerUdev::ScanDevices(DeviceEventObserver* observer) {
if (!enumerate)
return;
- for (size_t i = 0; i < arraysize(kSubsystems); ++i)
+ for (size_t i = 0; i < base::size(kSubsystems); ++i)
device::udev_enumerate_add_match_subsystem(enumerate.get(), kSubsystems[i]);
device::udev_enumerate_scan_devices(enumerate.get());
diff --git a/chromium/ui/events/ozone/evdev/capture_device_capabilities.py b/chromium/ui/events/ozone/evdev/capture_device_capabilities.py
index fd7aeee4972..e45d3d0839e 100755
--- a/chromium/ui/events/ozone/evdev/capture_device_capabilities.py
+++ b/chromium/ui/events/ozone/evdev/capture_device_capabilities.py
@@ -118,7 +118,7 @@ def dump_capabilities(out, dev, identifier=None):
if has_abs:
out.write(' %s,\n' % absinfo_identifier)
- out.write(' arraysize(%s),\n' % absinfo_identifier)
+ out.write(' base::size(%s),\n' % absinfo_identifier)
out.write('};\n')
diff --git a/chromium/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc b/chromium/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
index 44ee0430310..20658488b3e 100644
--- a/chromium/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
+++ b/chromium/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
@@ -11,8 +11,8 @@
#include "base/bind.h"
#include "base/files/scoped_file.h"
-#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
@@ -187,7 +187,7 @@ TEST_F(EventConverterEvdevImplTest, KeyPress) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(2u, size());
ui::KeyEvent* event;
@@ -224,7 +224,7 @@ TEST_F(EventConverterEvdevImplTest, KeyRepeat) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(2u, size());
ui::KeyEvent* event;
@@ -267,7 +267,7 @@ TEST_F(EventConverterEvdevImplTest, KeyWithModifier) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(4u, size());
ui::KeyEvent* event;
@@ -322,7 +322,7 @@ TEST_F(EventConverterEvdevImplTest, KeyWithDuplicateModifier) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(6u, size());
ui::KeyEvent* event;
@@ -371,7 +371,7 @@ TEST_F(EventConverterEvdevImplTest, KeyWithLock) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(2u, size());
ui::KeyEvent* event;
@@ -398,7 +398,7 @@ TEST_F(EventConverterEvdevImplTest, MouseButton) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(2u, size());
ui::MouseEvent* event;
@@ -430,7 +430,7 @@ TEST_F(EventConverterEvdevImplTest, MouseBackButton) {
{{0, 0}, EV_SYN, SYN_REPORT, 0}
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(2u, size());
ui::MouseEvent* event = nullptr;
@@ -462,7 +462,7 @@ TEST_F(EventConverterEvdevImplTest, MouseForwardButton) {
{{0, 0}, EV_SYN, SYN_REPORT, 0}
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(2u, size());
ui::MouseEvent* event = nullptr;
@@ -485,7 +485,7 @@ TEST_F(EventConverterEvdevImplTest, MouseMove) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(1u, size());
ui::MouseEvent* event;
@@ -506,7 +506,7 @@ TEST_F(EventConverterEvdevImplTest, UnmappedKeyPress) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(0u, size());
}
@@ -518,7 +518,7 @@ TEST_F(EventConverterEvdevImplTest, ShouldReleaseKeysOnUnplug) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(1u, size());
DestroyDevice();
@@ -543,7 +543,7 @@ TEST_F(EventConverterEvdevImplTest, ShouldReleaseKeysOnSynDropped) {
{{0, 0}, EV_SYN, SYN_DROPPED, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(2u, size());
ui::KeyEvent* event = dispatched_event(0);
@@ -563,7 +563,7 @@ TEST_F(EventConverterEvdevImplTest, ShouldReleaseKeysOnDisable) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(1u, size());
dev->SetEnabled(false);
@@ -596,7 +596,7 @@ TEST_F(EventConverterEvdevImplTest, SetAllowedKeys) {
{{0, 0}, EV_KEY, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
ASSERT_EQ(4u, size());
ui::KeyEvent* event = dispatched_event(0);
@@ -616,7 +616,7 @@ TEST_F(EventConverterEvdevImplTest, SetAllowedKeys) {
std::vector<ui::DomCode> allowed_keys;
allowed_keys.push_back(ui::DomCode::POWER);
dev->SetKeyFilter(true /* enable_filter */, allowed_keys);
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
ASSERT_EQ(2u, size());
event = dispatched_event(0);
@@ -628,7 +628,7 @@ TEST_F(EventConverterEvdevImplTest, SetAllowedKeys) {
ClearDispatchedEvents();
dev->SetKeyFilter(false /* enable_filter */, std::vector<ui::DomCode>());
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
event = dispatched_event(0);
EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
@@ -658,7 +658,7 @@ TEST_F(EventConverterEvdevImplTest, SetAllowedKeysBlockedKeyPressed) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(key_press, arraysize(key_press));
+ dev->ProcessEvents(key_press, base::size(key_press));
ASSERT_EQ(1u, size());
ui::KeyEvent* event = dispatched_event(0);
EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
@@ -674,7 +674,7 @@ TEST_F(EventConverterEvdevImplTest, SetAllowedKeysBlockedKeyPressed) {
// The real key release should be dropped, whenever it comes.
ClearDispatchedEvents();
- dev->ProcessEvents(key_release, arraysize(key_release));
+ dev->ProcessEvents(key_release, base::size(key_release));
ASSERT_EQ(0u, size());
}
@@ -701,7 +701,7 @@ TEST_F(EventConverterEvdevImplTest, ShouldSwapMouseButtonsFromUserPreference) {
SetTestNowSeconds(1510019415);
ClearDispatchedEvents();
GetInputController()->SetPrimaryButtonRight(false);
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(4u, size());
ui::MouseEvent* event;
@@ -741,7 +741,7 @@ TEST_F(EventConverterEvdevImplTest, ShouldSwapMouseButtonsFromUserPreference) {
ClearDispatchedEvents();
GetInputController()->SetPrimaryButtonRight(true);
- dev->ProcessEvents(mock_kernel_queue2, arraysize(mock_kernel_queue2));
+ dev->ProcessEvents(mock_kernel_queue2, base::size(mock_kernel_queue2));
EXPECT_EQ(4u, size());
event = dispatched_mouse_event(0);
diff --git a/chromium/ui/events/ozone/evdev/event_device_info.cc b/chromium/ui/events/ozone/evdev/event_device_info.cc
index 76085ec5484..4a001a73888 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info.cc
+++ b/chromium/ui/events/ozone/evdev/event_device_info.cc
@@ -8,7 +8,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/threading/thread_restrictions.h"
#include "ui/events/devices/device_util_linux.h"
@@ -198,35 +198,35 @@ bool EventDeviceInfo::Initialize(int fd, const base::FilePath& path) {
}
void EventDeviceInfo::SetEventTypes(const unsigned long* ev_bits, size_t len) {
- AssignBitset(ev_bits, len, ev_bits_, arraysize(ev_bits_));
+ AssignBitset(ev_bits, len, ev_bits_, base::size(ev_bits_));
}
void EventDeviceInfo::SetKeyEvents(const unsigned long* key_bits, size_t len) {
- AssignBitset(key_bits, len, key_bits_, arraysize(key_bits_));
+ AssignBitset(key_bits, len, key_bits_, base::size(key_bits_));
}
void EventDeviceInfo::SetRelEvents(const unsigned long* rel_bits, size_t len) {
- AssignBitset(rel_bits, len, rel_bits_, arraysize(rel_bits_));
+ AssignBitset(rel_bits, len, rel_bits_, base::size(rel_bits_));
}
void EventDeviceInfo::SetAbsEvents(const unsigned long* abs_bits, size_t len) {
- AssignBitset(abs_bits, len, abs_bits_, arraysize(abs_bits_));
+ AssignBitset(abs_bits, len, abs_bits_, base::size(abs_bits_));
}
void EventDeviceInfo::SetMscEvents(const unsigned long* msc_bits, size_t len) {
- AssignBitset(msc_bits, len, msc_bits_, arraysize(msc_bits_));
+ AssignBitset(msc_bits, len, msc_bits_, base::size(msc_bits_));
}
void EventDeviceInfo::SetSwEvents(const unsigned long* sw_bits, size_t len) {
- AssignBitset(sw_bits, len, sw_bits_, arraysize(sw_bits_));
+ AssignBitset(sw_bits, len, sw_bits_, base::size(sw_bits_));
}
void EventDeviceInfo::SetLedEvents(const unsigned long* led_bits, size_t len) {
- AssignBitset(led_bits, len, led_bits_, arraysize(led_bits_));
+ AssignBitset(led_bits, len, led_bits_, base::size(led_bits_));
}
void EventDeviceInfo::SetProps(const unsigned long* prop_bits, size_t len) {
- AssignBitset(prop_bits, len, prop_bits_, arraysize(prop_bits_));
+ AssignBitset(prop_bits, len, prop_bits_, base::size(prop_bits_));
}
void EventDeviceInfo::SetAbsInfo(unsigned int code,
@@ -458,11 +458,21 @@ bool EventDeviceInfo::HasGamepad() const {
// 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;
+ static constexpr struct {
+ uint16_t vid;
+ uint16_t pid;
+ } kUSBInternalDevices[] = {
+ { 0x18d1, 0x5030 }, // Google, Hammer PID
+ { 0x1fd2, 0x8103 } // LG, Internal TouchScreen PID
+ };
+
+ if (id.bustype == BUS_USB) {
+ for (size_t i = 0; i < base::size(kUSBInternalDevices); ++i) {
+ if (id.vendor == kUSBInternalDevices[i].vid &&
+ id.product == kUSBInternalDevices[i].pid)
+ return InputDeviceType::INPUT_DEVICE_INTERNAL;
+ }
+ }
switch (id.bustype) {
case BUS_I2C:
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 0d08e6a2906..1172b988fe2 100644
--- a/chromium/ui/events/ozone/evdev/event_device_test_util.cc
+++ b/chromium/ui/events/ozone/evdev/event_device_test_util.cc
@@ -7,7 +7,7 @@
#include <stdint.h>
#include "base/format_macros.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -106,7 +106,7 @@ const DeviceCapabilities kHJCGamepad = {
/* led */ "0",
/* ff */ "0",
kHJCGamepadAbsAxes,
- arraysize(kHJCGamepadAbsAxes),
+ base::size(kHJCGamepadAbsAxes),
};
// Captured from Xbox 360 gamepad.
@@ -140,7 +140,7 @@ const DeviceCapabilities kXboxGamepad = {
/* led */ "0",
/* ff */ "107030000 0",
kXboxGamepadAbsAxes,
- arraysize(kXboxGamepadAbsAxes),
+ base::size(kXboxGamepadAbsAxes),
};
// Captured from iBuffalo gamepad.
@@ -169,7 +169,7 @@ const DeviceCapabilities kiBuffaloGamepad = {
/* led */ "0",
/* ff */ "0",
kiBuffaloGamepadAbsAxes,
- arraysize(kiBuffaloGamepadAbsAxes),
+ base::size(kiBuffaloGamepadAbsAxes),
};
// Captured from Pixelbook.
@@ -208,7 +208,7 @@ const DeviceCapabilities kEveTouchScreen = {
/* led */ "0",
/* ff */ "0",
kEveTouchScreenAbsAxes,
- arraysize(kEveTouchScreenAbsAxes),
+ base::size(kEveTouchScreenAbsAxes),
};
// Captured from Chromebook Pixel.
@@ -246,8 +246,9 @@ const DeviceAbsoluteAxis kLinkTouchscreenAbsAxes[] = {
{ABS_MT_PRESSURE, {0, 0, 255, 0, 0, 0}},
};
const DeviceCapabilities kLinkTouchscreen = {
- /* path */ "/sys/devices/pci0000:00/0000:00:02.0/i2c-2/2-004a/"
- "input/input7/event7",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:02.0/i2c-2/2-004a/"
+ "input/input7/event7",
/* name */ "Atmel maXTouch Touchscreen",
/* phys */ "i2c-2-004a/input0",
/* uniq */ "",
@@ -265,7 +266,7 @@ const DeviceCapabilities kLinkTouchscreen = {
/* led */ "0",
/* ff */ "0",
kLinkTouchscreenAbsAxes,
- arraysize(kLinkTouchscreenAbsAxes),
+ base::size(kLinkTouchscreenAbsAxes),
};
// Fake Atmel touchscreen based on real device from Chromebook Pixel,
@@ -304,7 +305,7 @@ const DeviceCapabilities kLinkWithToolTypeTouchscreen = {
/* led */ "0",
/* ff */ "0",
kLinkWithToolTypeTouchscreenAbsAxes,
- arraysize(kLinkWithToolTypeTouchscreenAbsAxes),
+ base::size(kLinkWithToolTypeTouchscreenAbsAxes),
};
// Captured from Chromebook Pixel.
@@ -321,8 +322,9 @@ const DeviceAbsoluteAxis kLinkTouchpadAbsAxes[] = {
{ABS_MT_PRESSURE, {0, 0, 255, 0, 0, 0}},
};
const DeviceCapabilities kLinkTouchpad = {
- /* path */ "/sys/devices/pci0000:00/0000:00:02.0/i2c-1/1-004b/"
- "input/input8/event8",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:02.0/i2c-1/1-004b/"
+ "input/input8/event8",
/* name */ "Atmel maXTouch Touchpad",
/* phys */ "i2c-1-004b/input0",
/* uniq */ "",
@@ -340,7 +342,7 @@ const DeviceCapabilities kLinkTouchpad = {
/* led */ "0",
/* ff */ "0",
kLinkTouchpadAbsAxes,
- arraysize(kLinkTouchpadAbsAxes),
+ base::size(kLinkTouchpadAbsAxes),
};
// Captured from generic HP KU-1156 USB keyboard.
@@ -371,8 +373,9 @@ const DeviceAbsoluteAxis kHpUsbKeyboard_ExtraAbsAxes[] = {
{ABS_VOLUME, {0, 0, 767, 0, 0, 0}},
};
const DeviceCapabilities kHpUsbKeyboard_Extra = {
- /* path */ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/"
- "input/input18/event16",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/"
+ "input/input18/event16",
/* name */ "Chicony HP Elite USB Keyboard",
/* phys */ "usb-0000:00:1d.0-1.3/input1",
/* uniq */ "",
@@ -382,8 +385,9 @@ const DeviceCapabilities kHpUsbKeyboard_Extra = {
/* version */ "0110",
/* prop */ "0",
/* ev */ "1f",
- /* key */ "3007f 0 0 483ffff17aff32d bf54444600000000 1 120f938b17c000 "
- "677bfad941dfed 9ed68000004400 10000002",
+ /* key */
+ "3007f 0 0 483ffff17aff32d bf54444600000000 1 120f938b17c000 "
+ "677bfad941dfed 9ed68000004400 10000002",
/* rel */ "40",
/* abs */ "100000000",
/* msc */ "10",
@@ -391,7 +395,7 @@ const DeviceCapabilities kHpUsbKeyboard_Extra = {
/* led */ "0",
/* ff */ "0",
kHpUsbKeyboard_ExtraAbsAxes,
- arraysize(kHpUsbKeyboard_ExtraAbsAxes),
+ base::size(kHpUsbKeyboard_ExtraAbsAxes),
};
// Captured from Dell MS111-L 3-Button Optical USB Mouse.
@@ -422,8 +426,9 @@ const DeviceAbsoluteAxis kMimoTouch2TouchscreenAbsAxes[] = {
{ABS_Y, {0, 0, 2047, 0, 0, 0}},
};
const DeviceCapabilities kMimoTouch2Touchscreen = {
- /* path */ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3.2/"
- "2-1.3.2:1.0/input/input15/event14",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3.2/"
+ "2-1.3.2:1.0/input/input15/event14",
/* name */ "eGalax Inc. USB TouchController",
/* phys */ "usb-0000:00:1d.0-1.3.2/input0",
/* uniq */ "",
@@ -441,7 +446,7 @@ const DeviceCapabilities kMimoTouch2Touchscreen = {
/* led */ "0",
/* ff */ "0",
kMimoTouch2TouchscreenAbsAxes,
- arraysize(kMimoTouch2TouchscreenAbsAxes),
+ base::size(kMimoTouch2TouchscreenAbsAxes),
};
// Captured from Wacom Intuos Pen and Touch Small Tablet.
@@ -452,8 +457,9 @@ const DeviceAbsoluteAxis kWacomIntuosPtS_PenAbsAxes[] = {
{ABS_DISTANCE, {0, 0, 31, 0, 0, 0}},
};
const DeviceCapabilities kWacomIntuosPtS_Pen = {
- /* path */ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2.3/"
- "2-1.2.3:1.0/input/input9/event9",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2.3/"
+ "2-1.2.3:1.0/input/input9/event9",
/* name */ "Wacom Intuos PT S Pen",
/* phys */ "",
/* uniq */ "",
@@ -471,7 +477,7 @@ const DeviceCapabilities kWacomIntuosPtS_Pen = {
/* led */ "0",
/* ff */ "0",
kWacomIntuosPtS_PenAbsAxes,
- arraysize(kWacomIntuosPtS_PenAbsAxes),
+ base::size(kWacomIntuosPtS_PenAbsAxes),
};
// Captured from Wacom Intuos Pen and Touch Small Tablet.
@@ -486,8 +492,9 @@ const DeviceAbsoluteAxis kWacomIntuosPtS_FingerAbsAxes[] = {
{ABS_MT_TRACKING_ID, {0, 0, 65535, 0, 0, 0}},
};
const DeviceCapabilities kWacomIntuosPtS_Finger = {
- /* path */ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2.3/"
- "2-1.2.3:1.1/input/input10/event10",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2.3/"
+ "2-1.2.3:1.1/input/input10/event10",
/* name */ "Wacom Intuos PT S Finger",
/* phys */ "",
/* uniq */ "",
@@ -505,7 +512,7 @@ const DeviceCapabilities kWacomIntuosPtS_Finger = {
/* led */ "0",
/* ff */ "0",
kWacomIntuosPtS_FingerAbsAxes,
- arraysize(kWacomIntuosPtS_FingerAbsAxes),
+ base::size(kWacomIntuosPtS_FingerAbsAxes),
};
// Captured from Logitech Wireless Touch Keyboard K400.
@@ -513,8 +520,9 @@ const DeviceAbsoluteAxis kLogitechTouchKeyboardK400AbsAxes[] = {
{ABS_VOLUME, {0, 1, 652, 0, 0, 0}},
};
const DeviceCapabilities kLogitechTouchKeyboardK400 = {
- /* path */ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2.3/"
- "2-1.2.3:1.2/0003:046D:C52B.0006/input/input19/event17",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2.3/"
+ "2-1.2.3:1.2/0003:046D:C52B.0006/input/input19/event17",
/* name */ "Logitech Unifying Device. Wireless PID:4024",
/* phys */ "usb-0000:00:1d.0-1.2.3:1",
/* uniq */ "",
@@ -524,9 +532,10 @@ const DeviceCapabilities kLogitechTouchKeyboardK400 = {
/* version */ "0111",
/* prop */ "0",
/* ev */ "12001f",
- /* key */ "3007f 0 0 483ffff17aff32d bf54444600000000 ffff0001 "
- "130f938b17c007 ffff7bfad9415fff febeffdfffefffff "
- "fffffffffffffffe",
+ /* key */
+ "3007f 0 0 483ffff17aff32d bf54444600000000 ffff0001 "
+ "130f938b17c007 ffff7bfad9415fff febeffdfffefffff "
+ "fffffffffffffffe",
/* rel */ "1c3",
/* abs */ "100000000",
/* msc */ "10",
@@ -534,7 +543,7 @@ const DeviceCapabilities kLogitechTouchKeyboardK400 = {
/* led */ "1f",
/* ff */ "0",
kLogitechTouchKeyboardK400AbsAxes,
- arraysize(kLogitechTouchKeyboardK400AbsAxes),
+ base::size(kLogitechTouchKeyboardK400AbsAxes),
};
// Captured from Elo TouchSystems 2700 touchscreen.
@@ -544,10 +553,12 @@ const DeviceAbsoluteAxis kElo_TouchSystems_2700AbsAxes[] = {
{ABS_MISC, {0, 0, 256, 0, 0, 0}},
};
const DeviceCapabilities kElo_TouchSystems_2700 = {
- /* path */ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/"
- "input/input9/event9",
- /* name */ "Elo TouchSystems, Inc. Elo TouchSystems 2700 IntelliTouch(r) "
- "USB Touchmonitor Interface",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/"
+ "input/input9/event9",
+ /* name */
+ "Elo TouchSystems, Inc. Elo TouchSystems 2700 IntelliTouch(r) "
+ "USB Touchmonitor Interface",
/* phys */ "usb-0000:00:1d.0-1.3/input0",
/* uniq */ "20A01347",
/* bustype */ "0003",
@@ -564,7 +575,7 @@ const DeviceCapabilities kElo_TouchSystems_2700 = {
/* led */ "0",
/* ff */ "0",
kElo_TouchSystems_2700AbsAxes,
- arraysize(kElo_TouchSystems_2700AbsAxes),
+ base::size(kElo_TouchSystems_2700AbsAxes),
};
// Captured from Intel reference design: "Wilson Beach".
@@ -574,27 +585,28 @@ const DeviceAbsoluteAxis kWilsonBeachActiveStylusAbsAxes[] = {
{ABS_PRESSURE, {0, 0, 1024, 0, 0, 0}},
};
const DeviceCapabilities kWilsonBeachActiveStylus = {
- /* path */ "/sys/devices/pci0000:00/INT3433:00/i2c-1/"
+ /* path */
+ "/sys/devices/pci0000:00/INT3433:00/i2c-1/"
"i2c-NTRG0001:00/0018:1B96:0D03.0004/input/"
"input11/event10",
- /* name */ "NTRG0001:00 1B96:0D03 Pen",
- /* phys */ "",
- /* uniq */ "",
- /* bustype */ "0018",
- /* vendor */ "1b96",
- /* product */ "0d03",
- /* version */ "0100",
- /* prop */ "0",
- /* ev */ "1b",
- /* key */ "c03 1 0 0 0 0",
- /* rel */ "0",
- /* abs */ "1000003",
- /* msc */ "10",
- /* sw */ "0",
- /* led */ "0",
- /* ff */ "0",
- kWilsonBeachActiveStylusAbsAxes,
- arraysize(kWilsonBeachActiveStylusAbsAxes),
+ /* name */ "NTRG0001:00 1B96:0D03 Pen",
+ /* phys */ "",
+ /* uniq */ "",
+ /* bustype */ "0018",
+ /* vendor */ "1b96",
+ /* product */ "0d03",
+ /* version */ "0100",
+ /* prop */ "0",
+ /* ev */ "1b",
+ /* key */ "c03 1 0 0 0 0",
+ /* rel */ "0",
+ /* abs */ "1000003",
+ /* msc */ "10",
+ /* sw */ "0",
+ /* led */ "0",
+ /* ff */ "0",
+ kWilsonBeachActiveStylusAbsAxes,
+ base::size(kWilsonBeachActiveStylusAbsAxes),
};
// Captured from Eve Chromebook
@@ -624,7 +636,7 @@ const DeviceCapabilities kEveStylus = {
/* led */ "0",
/* ff */ "0",
kEveStylusAbsAxes,
- arraysize(kEveStylusAbsAxes),
+ base::size(kEveStylusAbsAxes),
};
const DeviceCapabilities kHammerKeyboard = {
@@ -685,7 +697,7 @@ const DeviceCapabilities kHammerTouchpad = {
/* led */ "0",
/* ff */ "0",
kHammerTouchpadAbsAxes,
- arraysize(kHammerTouchpadAbsAxes),
+ base::size(kHammerTouchpadAbsAxes),
};
// NB: Please use the capture_device_capabilities.py script to add more
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 3cb9f5dc11e..787848f9b60 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
@@ -17,9 +17,9 @@
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
-#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/time/time.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -169,7 +169,7 @@ TEST_F(GamepadEventConverterEvdevTest, XboxGamepadEvents) {
{GamepadEventType::BUTTON, 1, 0}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 2, 1}, {GamepadEventType::FRAME, 0, 0}};
- for (unsigned i = 0; i < arraysize(mock_kernel_queue); ++i) {
+ for (unsigned i = 0; i < base::size(mock_kernel_queue); ++i) {
dev->ProcessEvent(mock_kernel_queue[i]);
}
@@ -306,7 +306,7 @@ TEST_F(GamepadEventConverterEvdevTest, iBuffaloGamepadEvents) {
{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) {
+ for (unsigned i = 0; i < base::size(mock_kernel_queue); ++i) {
dev->ProcessEvent(mock_kernel_queue[i]);
}
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
index f7597bb4b53..bbfdf552453 100644
--- a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
@@ -8,7 +8,7 @@
#include <libevdev/libevdev.h>
#include <linux/input.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/timer/timer.h"
#include "ui/events/base_event_utils.h"
@@ -462,7 +462,7 @@ void GestureInterpreterLibevdevCros::DispatchChangedKeys(
unsigned long key_state_diff[EVDEV_BITS_TO_LONGS(KEY_CNT)];
// Find changed keys.
- for (unsigned long i = 0; i < arraysize(key_state_diff); ++i)
+ for (unsigned long i = 0; i < base::size(key_state_diff); ++i)
key_state_diff[i] = new_key_state[i] ^ prev_key_state_[i];
// Dispatch events for changed keys.
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
index d9252226aed..4e1385bd5e0 100644
--- a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
@@ -13,12 +13,11 @@
#include <algorithm>
#include <unordered_map>
-#include "base/containers/hash_tables.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
@@ -487,10 +486,10 @@ std::string GetDeviceNodePath(
// Check if a match criteria is currently implemented. Note that we didn't
// implemented all of them as some are inapplicable in the non-X world.
bool IsMatchTypeSupported(const std::string& match_type) {
- for (size_t i = 0; i < arraysize(kSupportedMatchTypes); ++i)
+ for (size_t i = 0; i < base::size(kSupportedMatchTypes); ++i)
if (match_type == kSupportedMatchTypes[i])
return true;
- for (size_t i = 0; i < arraysize(kUnsupportedMatchTypes); ++i) {
+ for (size_t i = 0; i < base::size(kUnsupportedMatchTypes); ++i) {
if (match_type == kUnsupportedMatchTypes[i]) {
LOG(ERROR) << "Unsupported gestures input class match type: "
<< match_type;
@@ -507,11 +506,11 @@ bool IsMatchDeviceType(const std::string& match_type) {
// Parse a boolean value keyword (e.g., on/off, true/false).
int ParseBooleanKeyword(const std::string& value) {
- for (size_t i = 0; i < arraysize(kTrue); ++i) {
+ for (size_t i = 0; i < base::size(kTrue); ++i) {
if (base::LowerCaseEqualsASCII(value, kTrue[i]))
return 1;
}
- for (size_t i = 0; i < arraysize(kFalse); ++i) {
+ for (size_t i = 0; i < base::size(kFalse); ++i) {
if (base::LowerCaseEqualsASCII(value, kFalse[i]))
return -1;
}
@@ -614,7 +613,7 @@ struct GestureDevicePropertyData {
// Unowned default properties (owned by the configuration file). Their values
// will be applied when a property of the same name is created. These are
// usually only a small portion of all properties in use.
- base::hash_map<std::string, GesturesProp*> default_properties;
+ std::unordered_map<std::string, GesturesProp*> default_properties;
};
// Base class for device match criterias in conf files.
diff --git a/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc
index 9018791e021..e3cc487c38f 100644
--- a/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc
+++ b/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc
@@ -16,10 +16,10 @@
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/posix/eintr_wrapper.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
@@ -51,8 +51,9 @@ const ui::DeviceAbsoluteAxis kWacomIntuos5SPenAbsAxes[] = {
};
const ui::DeviceCapabilities kWacomIntuos5SPen = {
- /* path */ "/sys/devices/pci0000:00/0000:00:14.0/usb1/"
- "1-1/1-1:1.0/input/input19/event5",
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:14.0/usb1/"
+ "1-1/1-1:1.0/input/input19/event5",
/* name */ "Wacom Intuos5 touch S Pen",
/* phys */ "",
/* uniq */ "",
@@ -70,10 +71,9 @@ const ui::DeviceCapabilities kWacomIntuos5SPen = {
/* led */ "0",
/* ff */ "0",
kWacomIntuos5SPenAbsAxes,
- arraysize(kWacomIntuos5SPenAbsAxes),
+ base::size(kWacomIntuos5SPenAbsAxes),
};
-
const ui::DeviceAbsoluteAxis EpsonBrightLink1430AbsAxes[] = {
{ABS_X, {0, 0, 32767, 0, 0, 200}},
{ABS_Y, {0, 0, 32767, 0, 0, 200}},
@@ -83,9 +83,10 @@ const ui::DeviceAbsoluteAxis EpsonBrightLink1430AbsAxes[] = {
};
const ui::DeviceCapabilities EpsonBrightLink1430 = {
- /* path */ "/sys/devices/ff580000.usb/usb3/3-1/"
- "3-1.1/3-1.1.3/3-1.1.3:1.1/0003:04B8:061B.0006/"
- "input/input12/event6",
+ /* path */
+ "/sys/devices/ff580000.usb/usb3/3-1/"
+ "3-1.1/3-1.1.3/3-1.1.3:1.1/0003:04B8:061B.0006/"
+ "input/input12/event6",
/* name */ "EPSON EPSON EPSON 1430",
/* phys */ "USB-ff580000.USB-1.1.3/input1",
/* uniq */ "2.04",
@@ -103,7 +104,7 @@ const ui::DeviceCapabilities EpsonBrightLink1430 = {
/* led */ "0",
/* ff */ "0",
EpsonBrightLink1430AbsAxes,
- arraysize(EpsonBrightLink1430AbsAxes),
+ base::size(EpsonBrightLink1430AbsAxes),
};
} // namespace
@@ -295,7 +296,7 @@ TEST_F(TabletEventConverterEvdevTest, MoveTopLeft) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(1u, size());
ui::MouseEvent* event = dispatched_event(0);
@@ -329,7 +330,7 @@ TEST_F(TabletEventConverterEvdevTest, MoveTopRight) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(1u, size());
ui::MouseEvent* event = dispatched_event(0);
@@ -364,7 +365,7 @@ TEST_F(TabletEventConverterEvdevTest, MoveBottomLeft) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(1u, size());
ui::MouseEvent* event = dispatched_event(0);
@@ -400,7 +401,7 @@ TEST_F(TabletEventConverterEvdevTest, MoveBottomRight) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(1u, size());
ui::MouseEvent* event = dispatched_event(0);
@@ -451,7 +452,7 @@ TEST_F(TabletEventConverterEvdevTest, Tap) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(3u, size());
ui::MouseEvent* event = dispatched_event(0);
@@ -513,7 +514,7 @@ TEST_F(TabletEventConverterEvdevTest, StylusButtonPress) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(3u, size());
ui::MouseEvent* event = dispatched_event(0);
@@ -537,7 +538,7 @@ TEST_F(TabletEventConverterEvdevTest, CheckStylusFiltering) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(0u, size());
}
@@ -584,7 +585,7 @@ TEST_F(TabletEventConverterEvdevTest, DigitizerPenOneSideButtonPress) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ dev->ProcessEvents(mock_kernel_queue, base::size(mock_kernel_queue));
EXPECT_EQ(3u, size());
ui::MouseEvent* event = dispatched_event(0);
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
index 3a59c13e225..4b04146b1ef 100644
--- a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
+++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
@@ -16,10 +16,10 @@
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
-#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/posix/eintr_wrapper.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/devices/device_data_manager.h"
@@ -345,7 +345,7 @@ TEST_F(TouchEventConverterEvdevTest, TouchMove) {
// Press.
dev->ConfigureReadMock(mock_kernel_queue_press,
- arraysize(mock_kernel_queue_press), 0);
+ base::size(mock_kernel_queue_press), 0);
dev->ReadNow();
EXPECT_EQ(1u, size());
ui::TouchEventParams event = dispatched_touch_event(0);
@@ -361,7 +361,7 @@ TEST_F(TouchEventConverterEvdevTest, TouchMove) {
// Move.
dev->ConfigureReadMock(mock_kernel_queue_move,
- arraysize(mock_kernel_queue_move), 0);
+ base::size(mock_kernel_queue_move), 0);
dev->ReadNow();
EXPECT_EQ(2u, size());
event = dispatched_touch_event(1);
@@ -377,7 +377,7 @@ TEST_F(TouchEventConverterEvdevTest, TouchMove) {
// Release.
dev->ConfigureReadMock(mock_kernel_queue_release,
- arraysize(mock_kernel_queue_release), 0);
+ base::size(mock_kernel_queue_release), 0);
dev->ReadNow();
EXPECT_EQ(3u, size());
event = dispatched_touch_event(2);
@@ -583,7 +583,7 @@ TEST_F(TouchEventConverterEvdevTest, ShouldResumeExistingContactsOnStart) {
};
dev->ConfigureReadMock(mock_kernel_queue_empty_report,
- arraysize(mock_kernel_queue_empty_report), 0);
+ base::size(mock_kernel_queue_empty_report), 0);
dev->ReadNow();
EXPECT_EQ(1u, size());
@@ -620,7 +620,7 @@ TEST_F(TouchEventConverterEvdevTest, ShouldReleaseContactsOnStop) {
SetTestNowTime(time);
dev->ConfigureReadMock(mock_kernel_queue_press,
- arraysize(mock_kernel_queue_press), 0);
+ base::size(mock_kernel_queue_press), 0);
dev->ReadNow();
EXPECT_EQ(1u, size());
@@ -665,7 +665,7 @@ TEST_F(TouchEventConverterEvdevTest, ShouldRemoveContactsWhenDisabled) {
dev->Initialize(devinfo);
dev->ConfigureReadMock(mock_kernel_queue_press,
- arraysize(mock_kernel_queue_press), 0);
+ base::size(mock_kernel_queue_press), 0);
dev->ReadNow();
EXPECT_EQ(1u, size());
@@ -697,7 +697,7 @@ TEST_F(TouchEventConverterEvdevTest, ShouldRemoveContactsWhenDisabled) {
// Send updates to touch (touch is cancelled, should not come back)
dev->ConfigureReadMock(mock_kernel_queue_press,
- arraysize(mock_kernel_queue_press), 0);
+ base::size(mock_kernel_queue_press), 0);
dev->ReadNow();
EXPECT_EQ(2u, size());
}
@@ -773,7 +773,7 @@ TEST_F(TouchEventConverterEvdevTest, PalmShouldCancelTouch) {
dev->Initialize(devinfo);
dev->ConfigureReadMock(mock_kernel_queue_max_major,
- arraysize(mock_kernel_queue_max_major), 0);
+ base::size(mock_kernel_queue_max_major), 0);
dev->ReadNow();
EXPECT_EQ(4u, size());
@@ -800,7 +800,7 @@ TEST_F(TouchEventConverterEvdevTest, PalmShouldCancelTouch) {
EXPECT_EQ(1, ev1_4.slot);
dev->ConfigureReadMock(mock_kernel_queue_tool_palm,
- arraysize(mock_kernel_queue_tool_palm), 0);
+ base::size(mock_kernel_queue_tool_palm), 0);
dev->ReadNow();
EXPECT_EQ(8u, size());
@@ -934,7 +934,7 @@ TEST_F(TouchEventConverterEvdevTest, TrackingIdShouldNotResetCancelByPalm) {
dev->Initialize(devinfo);
dev->ConfigureReadMock(mock_kernel_queue_max_major,
- arraysize(mock_kernel_queue_max_major), 0);
+ base::size(mock_kernel_queue_max_major), 0);
dev->ReadNow();
EXPECT_EQ(4u, size());
@@ -961,12 +961,13 @@ TEST_F(TouchEventConverterEvdevTest, TrackingIdShouldNotResetCancelByPalm) {
EXPECT_EQ(1, ev1_4.slot);
dev->ConfigureReadMock(mock_kernel_new_touch_without_new_major,
- arraysize(mock_kernel_new_touch_without_new_major), 0);
+ base::size(mock_kernel_new_touch_without_new_major),
+ 0);
dev->ReadNow();
EXPECT_EQ(4u, size());
dev->ConfigureReadMock(mock_kernel_queue_tool_palm,
- arraysize(mock_kernel_queue_tool_palm), 0);
+ base::size(mock_kernel_queue_tool_palm), 0);
dev->ReadNow();
EXPECT_EQ(8u, size());
@@ -1034,7 +1035,7 @@ TEST_F(TouchEventConverterEvdevTest, ShouldUseLeftButtonIfNoTouchButton) {
// Press.
dev->ConfigureReadMock(mock_kernel_queue_press,
- arraysize(mock_kernel_queue_press), 0);
+ base::size(mock_kernel_queue_press), 0);
dev->ReadNow();
EXPECT_EQ(1u, size());
ui::TouchEventParams event = dispatched_touch_event(0);
@@ -1048,7 +1049,7 @@ TEST_F(TouchEventConverterEvdevTest, ShouldUseLeftButtonIfNoTouchButton) {
// Move.
dev->ConfigureReadMock(mock_kernel_queue_move,
- arraysize(mock_kernel_queue_move), 0);
+ base::size(mock_kernel_queue_move), 0);
dev->ReadNow();
EXPECT_EQ(2u, size());
event = dispatched_touch_event(1);
@@ -1062,7 +1063,7 @@ TEST_F(TouchEventConverterEvdevTest, ShouldUseLeftButtonIfNoTouchButton) {
// Release.
dev->ConfigureReadMock(mock_kernel_queue_release,
- arraysize(mock_kernel_queue_release), 0);
+ base::size(mock_kernel_queue_release), 0);
dev->ReadNow();
EXPECT_EQ(3u, size());
event = dispatched_touch_event(2);
@@ -1104,7 +1105,7 @@ TEST_F(TouchEventConverterEvdevTest,
};
// Check that two events are generated.
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
const unsigned int kExpectedEventCount = 2;
@@ -1145,7 +1146,7 @@ TEST_F(TouchEventConverterEvdevTest, CheckSlotLimit) {
};
// Check that one 1 event is generated
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
EXPECT_EQ(1u, size());
}
@@ -1251,14 +1252,14 @@ TEST_F(TouchEventConverterEvdevTouchNoiseTest, TouchNoiseFiltering) {
MockTouchEventConverterEvdev* dev = device();
SetTouchNoiseFilter(std::unique_ptr<TouchFilter>(
new EventTypeTouchNoiseFilter(ET_TOUCH_PRESSED)));
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
ASSERT_EQ(0u, size());
ClearDispatchedEvents();
SetTouchNoiseFilter(std::unique_ptr<TouchFilter>(
new EventTypeTouchNoiseFilter(ET_TOUCH_MOVED)));
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
ASSERT_EQ(2u, size());
TouchEventParams event0 = dispatched_touch_event(0);
@@ -1270,7 +1271,7 @@ TEST_F(TouchEventConverterEvdevTouchNoiseTest, TouchNoiseFiltering) {
ClearDispatchedEvents();
SetTouchNoiseFilter(std::unique_ptr<TouchFilter>(
new EventTypeTouchNoiseFilter(ET_TOUCH_RELEASED)));
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
ASSERT_EQ(3u, size());
event0 = dispatched_touch_event(0);
@@ -1309,7 +1310,7 @@ TEST_F(TouchEventConverterEvdevTouchNoiseTest,
MockTouchEventConverterEvdev* dev = device();
SetTouchNoiseFilter(std::unique_ptr<TouchFilter>(
new EventTypeTouchNoiseFilter(ET_TOUCH_PRESSED)));
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
ASSERT_EQ(0u, size());
@@ -1343,7 +1344,7 @@ TEST_F(TouchEventConverterEvdevTest, ActiveStylusTouchAndRelease) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
EXPECT_EQ(2u, size());
@@ -1393,7 +1394,7 @@ TEST_F(TouchEventConverterEvdevTest, ActiveStylusMotion) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
EXPECT_EQ(4u, size());
@@ -1462,7 +1463,7 @@ TEST_F(TouchEventConverterEvdevTest, ActiveStylusBarrelButtonWhileHovering) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
EXPECT_EQ(2u, size());
@@ -1511,7 +1512,7 @@ TEST_F(TouchEventConverterEvdevTest, ActiveStylusBarrelButton) {
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
EXPECT_EQ(4u, size());
@@ -1569,7 +1570,7 @@ TEST_F(TouchEventConverterEvdevTest, FingerSizeWithResolution) {
SetTestNowTime(time);
// Finger pressed with major/minor reported.
- dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
+ dev->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), 0);
dev->ReadNow();
EXPECT_EQ(1u, size());
ui::TouchEventParams event = dispatched_touch_event(0);
diff --git a/chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder_unittest.cc b/chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder_unittest.cc
index e0df4ec3b4d..8c9fec67265 100644
--- a/chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder_unittest.cc
+++ b/chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder_unittest.cc
@@ -11,7 +11,7 @@
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_switches.h"
@@ -110,7 +110,7 @@ TEST_F(FalseTouchFinderTest, FarApartTaps) {
{50, 1, true, gfx::PointF(10, 14), 0.35, true, false},
{50, 2, false, gfx::PointF(2500, 1002), 0.35, true, false},
{60, 1, false, gfx::PointF(10, 15), 0.35, true, false}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that taps which are far apart but do not occur in quick succession are
@@ -125,7 +125,7 @@ TEST_F(FalseTouchFinderTest, FarApartTapsSlow) {
{3000, 1, true, gfx::PointF(10, 14), 0.35, false, false},
{3000, 2, false, gfx::PointF(2500, 1001), 0.35, false, false},
{3500, 1, false, gfx::PointF(10, 15), 0.35, false, false}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that touches which are horizontally aligned are considered noise.
@@ -137,7 +137,7 @@ TEST_F(FalseTouchFinderTest, HorizontallyAligned) {
{30, 1, false, gfx::PointF(10, 10), 0.35, false, false},
{30, 2, true, gfx::PointF(10, 25), 0.35, true, false},
{40, 2, false, gfx::PointF(10, 25), 0.35, true, false}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that touches in the same position are considered noise.
@@ -154,7 +154,7 @@ TEST_F(FalseTouchFinderTest, SamePosition) {
{4000, 2, false, gfx::PointF(10, 10), 0.35, true, false},
{4500, 1, true, gfx::PointF(10, 10), 0.35, true, false},
{5000, 1, false, gfx::PointF(10, 10), 0.35, true, false}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that a multi-second touch is considered noise.
@@ -166,7 +166,7 @@ TEST_F(FalseTouchFinderTest, MultiSecondTouch) {
{4000, 1, true, gfx::PointF(10, 11), 0.35, true, false},
{5000, 1, true, gfx::PointF(10, 10), 0.35, true, false},
{6000, 1, true, gfx::PointF(10, 11), 0.35, true, false}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that a touch on the edge which never leaves is delayed and never
@@ -187,7 +187,7 @@ TEST_F(FalseTouchFinderTest, EdgeTap) {
{100, 4, true, gfx::PointF(100, ts_height - 1), 0.35, false, true},
{110, 4, true, gfx::PointF(100, ts_height - 1), 0.35, false, true},
{120, 4, false, gfx::PointF(100, ts_height - 1), 0.35, false, true}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that a touch on the edge which starts at an edge is delayed but released
@@ -202,7 +202,7 @@ TEST_F(FalseTouchFinderTest, MoveFromEdge) {
{60, 1, true, gfx::PointF(0, 100), 0.35, false, true},
{70, 1, true, gfx::PointF(0, 101), 0.35, false, false},
{80, 1, false, gfx::PointF(0, 101), 0.35, false, false}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that a touch on the edge which starts away from the edge is not
@@ -213,7 +213,7 @@ TEST_F(FalseTouchFinderTest, MoveToEdge) {
{20, 1, true, gfx::PointF(100, 100), 0.35, false, false},
{30, 1, true, gfx::PointF(0, 100), 0.35, false, false},
{40, 1, false, gfx::PointF(0, 100), 0.35, false, false}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that a pencil with a wide tip should be filtered out. Based on real
@@ -225,7 +225,7 @@ TEST_F(FalseTouchFinderTest, FatPencilPressure) {
{30, 1, true, gfx::PointF(10, 10), 0.180392, false, true},
{40, 1, true, gfx::PointF(10, 10), 0.164706, false, true},
{50, 1, true, gfx::PointF(10, 10), 0.101961, false, true}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
// Test that a pinky finger lightly pressed is not filtered out. Based on real
@@ -237,7 +237,7 @@ TEST_F(FalseTouchFinderTest, LightPinkyPressure) {
{30, 1, true, gfx::PointF(10, 10), 0.215686, false, false},
{40, 1, true, gfx::PointF(10, 10), 0.211765, false, false},
{50, 1, true, gfx::PointF(10, 10), 0.203922, false, false}};
- EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
+ EXPECT_TRUE(FilterAndCheck(kTestData, base::size(kTestData)));
}
} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/touch_filter/far_apart_taps_touch_noise_filter.cc b/chromium/ui/events/ozone/evdev/touch_filter/far_apart_taps_touch_noise_filter.cc
index 6e8b0752a0f..9078fbde62f 100644
--- a/chromium/ui/events/ozone/evdev/touch_filter/far_apart_taps_touch_noise_filter.cc
+++ b/chromium/ui/events/ozone/evdev/touch_filter/far_apart_taps_touch_noise_filter.cc
@@ -9,8 +9,8 @@
#include <cmath>
#include "base/logging.h"
-#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
namespace ui {
@@ -48,7 +48,7 @@ void FarApartTapsTouchNoiseFilter::Filter(
// Remove old taps.
base::TimeTicks tap_cutoff =
time - base::TimeDelta::FromMilliseconds(kMaxTapDeltaMs);
- for (size_t i = 0; i < arraysize(tracked_taps_); ++i) {
+ for (size_t i = 0; i < base::size(tracked_taps_); ++i) {
if (tracked_taps_[i].start < tap_cutoff)
tracked_taps_[i].Invalidate();
}
@@ -73,7 +73,7 @@ void FarApartTapsTouchNoiseFilter::Filter(
if (tracked_taps_[slot].is_valid()) {
// Check distance from other tracked taps.
int min_distance2 = -1;
- for (size_t i = 0; i < arraysize(tracked_taps_); ++i) {
+ for (size_t i = 0; i < base::size(tracked_taps_); ++i) {
if (i == slot || !tracked_taps_[i].is_valid())
continue;
diff --git a/chromium/ui/events/ozone/gamepad/static_gamepad_mapping.cc b/chromium/ui/events/ozone/gamepad/static_gamepad_mapping.cc
index 79f699a1f2d..6cf8dcca02b 100644
--- a/chromium/ui/events/ozone/gamepad/static_gamepad_mapping.cc
+++ b/chromium/ui/events/ozone/gamepad/static_gamepad_mapping.cc
@@ -8,7 +8,7 @@
#include <map>
#include <vector>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "ui/events/ozone/evdev/event_device_info.h"
#include "ui/events/ozone/gamepad/static_gamepad_mapping.h"
#include "ui/events/ozone/gamepad/webgamepad_constants.h"
@@ -20,9 +20,9 @@ typedef bool (*GamepadMapperFunction)(uint16_t key,
GamepadEventType* mapped_type,
uint16_t* mapped_code);
-#define DO_MAPPING \
- DoGamepadMapping(key_mapping, arraysize(key_mapping), abs_mapping, \
- arraysize(abs_mapping), type, code, mapped_type, \
+#define DO_MAPPING \
+ DoGamepadMapping(key_mapping, base::size(key_mapping), abs_mapping, \
+ base::size(abs_mapping), type, code, mapped_type, \
mapped_code)
bool DoGamepadMapping(const KeyMapEntry* key_mapping,
@@ -523,7 +523,7 @@ class StaticGamepadMapper : public GamepadMapper {
};
GamepadMapper* GetStaticGamepadMapper(uint16_t vendor_id, uint16_t product_id) {
- for (size_t i = 0; i < arraysize(AvailableMappings); i++) {
+ for (size_t i = 0; i < base::size(AvailableMappings); i++) {
if (AvailableMappings[i].vendor_id == vendor_id &&
AvailableMappings[i].product_id == product_id) {
return new StaticGamepadMapper(AvailableMappings[i].mapper);
diff --git a/chromium/ui/events/ozone/layout/keyboard_layout_engine_manager.cc b/chromium/ui/events/ozone/layout/keyboard_layout_engine_manager.cc
index 735aac19d93..6e3e8c29b35 100644
--- a/chromium/ui/events/ozone/layout/keyboard_layout_engine_manager.cc
+++ b/chromium/ui/events/ozone/layout/keyboard_layout_engine_manager.cc
@@ -24,6 +24,7 @@ KeyboardLayoutEngineManager::~KeyboardLayoutEngineManager() {
instance_ = NULL;
}
+// static
void KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
std::unique_ptr<KeyboardLayoutEngine> engine) {
if (instance_)
@@ -32,6 +33,7 @@ void KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
new KeyboardLayoutEngineManager(engine.release());
}
+// static
KeyboardLayoutEngine* KeyboardLayoutEngineManager::GetKeyboardLayoutEngine() {
// TODO(kpschoedel): crbug.com/430194 This lazy initialization is a
// workaround for not yet initializing KeyboardLayoutEngineManager
diff --git a/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc b/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
index afeec925722..d8185a0269e 100644
--- a/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
+++ b/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
@@ -12,9 +12,9 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/free_deleter.h"
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "base/task/post_task.h"
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -487,64 +487,64 @@ struct PrintableMultiEntry {
// Entries are ordered by character value.
const PrintableMultiEntry kMultiMap[] = {
- {0x0021, kU0021, arraysize(kU0021)}, // exclamation mark
- {0x0022, kU0022, arraysize(kU0022)}, // quotation mark
- {0x0023, kU0023, arraysize(kU0023)}, // number sign
- {0x0024, kU0024, arraysize(kU0024)}, // dollar sign
- {0x0027, kU0027, arraysize(kU0027)}, // apostrophe
- {0x0028, kU0028, arraysize(kU0028)}, // left parenthesis
- {0x0029, kU0029, arraysize(kU0029)}, // right parenthesis
- {0x002A, kU002A, arraysize(kU002A)}, // asterisk
- {0x002B, kU002B, arraysize(kU002B)}, // plus sign
- {0x002C, kU002C, arraysize(kU002C)}, // comma
- {0x002D, kU002D, arraysize(kU002D)}, // hyphen-minus
- {0x002E, kU002E, arraysize(kU002E)}, // full stop
- {0x002F, kU002F, arraysize(kU002F)}, // solidus
- {0x003A, kU003A, arraysize(kU003A)}, // colon
- {0x003B, kU003B, arraysize(kU003B)}, // semicolon
- {0x003D, kU003D, arraysize(kU003D)}, // equals sign
- {0x003F, kU003F, arraysize(kU003F)}, // question mark
- {0x0040, kU0040, arraysize(kU0040)}, // commercial at
- {0x005B, kU005B, arraysize(kU005B)}, // left square bracket
- {0x005C, kU005C, arraysize(kU005C)}, // reverse solidus
- {0x005D, kU005D, arraysize(kU005D)}, // right square bracket
- {0x005F, kU005F, arraysize(kU005F)}, // low line
- {0x0060, kU0060, arraysize(kU0060)}, // grave accent
- {0x00A7, kU00A7, arraysize(kU00A7)}, // section sign
- {0x00AB, kU00AB, arraysize(kU00AB)}, // left double angle quotation mark
- {0x00B0, kU00B0, arraysize(kU00B0)}, // degree sign
- {0x00BA, kU00BA, arraysize(kU00BA)}, // masculine ordinal indicator
- {0x00E0, kU00E0, arraysize(kU00E0)}, // a grave
- {0x00E1, kU00E1, arraysize(kU00E1)}, // a acute
- {0x00E2, kU00E2, arraysize(kU00E2)}, // a circumflex
- {0x00E4, kU00E4, arraysize(kU00E4)}, // a diaeresis
- {0x00E6, kU00E6, arraysize(kU00E6)}, // ae
- {0x00E7, kU00E7, arraysize(kU00E7)}, // c cedilla
- {0x00E8, kU00E8, arraysize(kU00E8)}, // e grave
- {0x00E9, kU00E9, arraysize(kU00E9)}, // e acute
- {0x00ED, kU00ED, arraysize(kU00ED)}, // i acute
- {0x00F0, kU00F0, arraysize(kU00F0)}, // eth
- {0x00F3, kU00F3, arraysize(kU00F3)}, // o acute
- {0x00F4, kU00F4, arraysize(kU00F4)}, // o circumflex
- {0x00F6, kU00F6, arraysize(kU00F6)}, // o diaeresis
- {0x00F8, kU00F8, arraysize(kU00F8)}, // o stroke
- {0x00F9, kU00F9, arraysize(kU00F9)}, // u grave
- {0x00FA, kU00FA, arraysize(kU00FA)}, // u acute
- {0x00FC, kU00FC, arraysize(kU00FC)}, // u diaeresis
- {0x0103, kU0103, arraysize(kU0103)}, // a breve
- {0x0105, kU0105, arraysize(kU0105)}, // a ogonek
- {0x010D, kU010D, arraysize(kU010D)}, // c caron
- {0x0111, kU0111, arraysize(kU0111)}, // d stroke
- {0x0117, kU0117, arraysize(kU0117)}, // e dot above
- {0x0119, kU0119, arraysize(kU0119)}, // e ogonek
- {0x012F, kU012F, arraysize(kU012F)}, // i ogonek
- {0x0142, kU0142, arraysize(kU0142)}, // l stroke
- {0x015F, kU015F, arraysize(kU015F)}, // s cedilla
- {0x0161, kU0161, arraysize(kU0161)}, // s caron
- {0x016B, kU016B, arraysize(kU016B)}, // u macron
- {0x0173, kU0173, arraysize(kU0173)}, // u ogonek
- {0x017C, kU017C, arraysize(kU017C)}, // z dot above
- {0x017E, kU017E, arraysize(kU017E)}, // z caron
+ {0x0021, kU0021, base::size(kU0021)}, // exclamation mark
+ {0x0022, kU0022, base::size(kU0022)}, // quotation mark
+ {0x0023, kU0023, base::size(kU0023)}, // number sign
+ {0x0024, kU0024, base::size(kU0024)}, // dollar sign
+ {0x0027, kU0027, base::size(kU0027)}, // apostrophe
+ {0x0028, kU0028, base::size(kU0028)}, // left parenthesis
+ {0x0029, kU0029, base::size(kU0029)}, // right parenthesis
+ {0x002A, kU002A, base::size(kU002A)}, // asterisk
+ {0x002B, kU002B, base::size(kU002B)}, // plus sign
+ {0x002C, kU002C, base::size(kU002C)}, // comma
+ {0x002D, kU002D, base::size(kU002D)}, // hyphen-minus
+ {0x002E, kU002E, base::size(kU002E)}, // full stop
+ {0x002F, kU002F, base::size(kU002F)}, // solidus
+ {0x003A, kU003A, base::size(kU003A)}, // colon
+ {0x003B, kU003B, base::size(kU003B)}, // semicolon
+ {0x003D, kU003D, base::size(kU003D)}, // equals sign
+ {0x003F, kU003F, base::size(kU003F)}, // question mark
+ {0x0040, kU0040, base::size(kU0040)}, // commercial at
+ {0x005B, kU005B, base::size(kU005B)}, // left square bracket
+ {0x005C, kU005C, base::size(kU005C)}, // reverse solidus
+ {0x005D, kU005D, base::size(kU005D)}, // right square bracket
+ {0x005F, kU005F, base::size(kU005F)}, // low line
+ {0x0060, kU0060, base::size(kU0060)}, // grave accent
+ {0x00A7, kU00A7, base::size(kU00A7)}, // section sign
+ {0x00AB, kU00AB, base::size(kU00AB)}, // left double angle quotation mark
+ {0x00B0, kU00B0, base::size(kU00B0)}, // degree sign
+ {0x00BA, kU00BA, base::size(kU00BA)}, // masculine ordinal indicator
+ {0x00E0, kU00E0, base::size(kU00E0)}, // a grave
+ {0x00E1, kU00E1, base::size(kU00E1)}, // a acute
+ {0x00E2, kU00E2, base::size(kU00E2)}, // a circumflex
+ {0x00E4, kU00E4, base::size(kU00E4)}, // a diaeresis
+ {0x00E6, kU00E6, base::size(kU00E6)}, // ae
+ {0x00E7, kU00E7, base::size(kU00E7)}, // c cedilla
+ {0x00E8, kU00E8, base::size(kU00E8)}, // e grave
+ {0x00E9, kU00E9, base::size(kU00E9)}, // e acute
+ {0x00ED, kU00ED, base::size(kU00ED)}, // i acute
+ {0x00F0, kU00F0, base::size(kU00F0)}, // eth
+ {0x00F3, kU00F3, base::size(kU00F3)}, // o acute
+ {0x00F4, kU00F4, base::size(kU00F4)}, // o circumflex
+ {0x00F6, kU00F6, base::size(kU00F6)}, // o diaeresis
+ {0x00F8, kU00F8, base::size(kU00F8)}, // o stroke
+ {0x00F9, kU00F9, base::size(kU00F9)}, // u grave
+ {0x00FA, kU00FA, base::size(kU00FA)}, // u acute
+ {0x00FC, kU00FC, base::size(kU00FC)}, // u diaeresis
+ {0x0103, kU0103, base::size(kU0103)}, // a breve
+ {0x0105, kU0105, base::size(kU0105)}, // a ogonek
+ {0x010D, kU010D, base::size(kU010D)}, // c caron
+ {0x0111, kU0111, base::size(kU0111)}, // d stroke
+ {0x0117, kU0117, base::size(kU0117)}, // e dot above
+ {0x0119, kU0119, base::size(kU0119)}, // e ogonek
+ {0x012F, kU012F, base::size(kU012F)}, // i ogonek
+ {0x0142, kU0142, base::size(kU0142)}, // l stroke
+ {0x015F, kU015F, base::size(kU015F)}, // s cedilla
+ {0x0161, kU0161, base::size(kU0161)}, // s caron
+ {0x016B, kU016B, base::size(kU016B)}, // u macron
+ {0x0173, kU0173, base::size(kU0173)}, // u ogonek
+ {0x017C, kU017C, base::size(kU017C)}, // z dot above
+ {0x017E, kU017E, base::size(kU017E)}, // z caron
};
// Table mapping unshifted characters to VKEY values.
@@ -825,8 +825,8 @@ void XkbKeyboardLayoutEngine::SetKeymap(xkb_keymap* keymap) {
{ui::EF_MOD3_DOWN, "Mod3"},
{ui::EF_CAPS_LOCK_ON, XKB_MOD_NAME_CAPS}};
xkb_flag_map_.clear();
- xkb_flag_map_.reserve(arraysize(flags));
- for (size_t i = 0; i < arraysize(flags); ++i) {
+ xkb_flag_map_.reserve(base::size(flags));
+ for (size_t i = 0; i < base::size(flags); ++i) {
xkb_mod_index_t index = xkb_keymap_mod_get_index(keymap, flags[i].xkb_name);
if (index == XKB_MOD_INVALID) {
DVLOG(3) << "XKB keyboard layout does not contain " << flags[i].xkb_name;
@@ -898,7 +898,7 @@ KeyboardCode XkbKeyboardLayoutEngine::DifficultKeyboardCode(
return key_code;
// Check the multi-character tables.
- const PrintableMultiEntry* multi_end = kMultiMap + arraysize(kMultiMap);
+ const PrintableMultiEntry* multi_end = kMultiMap + base::size(kMultiMap);
const PrintableMultiEntry* multi =
std::lower_bound(kMultiMap, multi_end, plain_character,
[](const PrintableMultiEntry& e, base::char16 c) {
@@ -932,7 +932,7 @@ KeyboardCode XkbKeyboardLayoutEngine::DifficultKeyboardCode(
}
// Check the simple character table.
- const PrintableSimpleEntry* simple_end = kSimpleMap + arraysize(kSimpleMap);
+ const PrintableSimpleEntry* simple_end = kSimpleMap + base::size(kSimpleMap);
const PrintableSimpleEntry* simple =
std::lower_bound(kSimpleMap, simple_end, plain_character,
[](const PrintableSimpleEntry& e, base::char16 c) {
diff --git a/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h b/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
index 4869af535e7..50f09128ec0 100644
--- a/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
+++ b/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
@@ -11,7 +11,6 @@
#include <memory>
#include <vector>
-#include "base/containers/hash_tables.h"
#include "base/memory/free_deleter.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
diff --git a/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc b/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
index 0830460bc98..9f6f20d6f03 100644
--- a/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
+++ b/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
@@ -7,7 +7,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
@@ -65,8 +65,8 @@ class VkTestXkbKeyboardLayoutEngine : public XkbKeyboardLayoutEngine {
static const int kTestFlags[] = {EF_SHIFT_DOWN, EF_ALTGR_DOWN,
EF_MOD3_DOWN};
xkb_flag_map_.clear();
- xkb_flag_map_.resize(arraysize(kTestFlags));
- for (size_t i = 0; i < arraysize(kTestFlags); ++i) {
+ xkb_flag_map_.resize(base::size(kTestFlags));
+ for (size_t i = 0; i < base::size(kTestFlags); ++i) {
XkbFlagMapEntry e = {kTestFlags[i], kTestFlags[i]};
xkb_flag_map_.push_back(e);
}
@@ -767,7 +767,7 @@ TEST_F(XkbLayoutEngineVkTest, KeyboardCodeForPrintable) {
/* 296 */ {{'0', ')', '-', DomCode::NONE}, VKEY_0},
};
- for (size_t i = 0; i < arraysize(kVkeyTestCase); ++i) {
+ for (size_t i = 0; i < base::size(kVkeyTestCase); ++i) {
SCOPED_TRACE(i);
const auto& e = kVkeyTestCase[i];
layout_engine_->SetEntry(&e.test);
@@ -896,7 +896,7 @@ TEST_F(XkbLayoutEngineVkTest, XkbRuleNamesForLayoutName) {
/* 50 */ {"ge", "ge", ""},
/* 51 */ {"mn", "mn", ""},
/* 52 */ {"ie", "ie", ""}};
- for (size_t i = 0; i < arraysize(kVkeyTestCase); ++i) {
+ for (size_t i = 0; i < base::size(kVkeyTestCase); ++i) {
SCOPED_TRACE(i);
const VkTestXkbKeyboardLayoutEngine::RuleNames* e = &kVkeyTestCase[i];
std::string layout_id;
diff --git a/chromium/ui/events/platform/platform_event_source.cc b/chromium/ui/events/platform/platform_event_source.cc
index a1d84b69106..dfded71d596 100644
--- a/chromium/ui/events/platform/platform_event_source.cc
+++ b/chromium/ui/events/platform/platform_event_source.cc
@@ -24,6 +24,8 @@ base::LazyInstance<base::ThreadLocalPointer<PlatformEventSource>>::Leaky
} // namespace
+bool PlatformEventSource::ignore_native_platform_events_ = false;
+
PlatformEventSource::PlatformEventSource()
: overridden_dispatcher_(NULL),
overridden_dispatcher_restored_(false) {
@@ -41,6 +43,14 @@ PlatformEventSource* PlatformEventSource::GetInstance() {
return lazy_tls_ptr.Pointer()->Get();
}
+bool PlatformEventSource::ShouldIgnoreNativePlatformEvents() {
+ return ignore_native_platform_events_;
+}
+
+void PlatformEventSource::SetIgnoreNativePlatformEvents(bool ignore_events) {
+ ignore_native_platform_events_ = ignore_events;
+}
+
void PlatformEventSource::AddPlatformEventDispatcher(
PlatformEventDispatcher* dispatcher) {
CHECK(dispatcher);
diff --git a/chromium/ui/events/platform/platform_event_source.h b/chromium/ui/events/platform/platform_event_source.h
index 1dbec3b88dd..7bd60d08a46 100644
--- a/chromium/ui/events/platform/platform_event_source.h
+++ b/chromium/ui/events/platform/platform_event_source.h
@@ -36,6 +36,16 @@ class EVENTS_EXPORT PlatformEventSource {
// Returns the thread-local singleton.
static PlatformEventSource* GetInstance();
+ // Returns true when platform events should not be sent to the rest of the
+ // pipeline. Mainly when Chrome is run in a test environment and it doesn't
+ // expect any events from the platform and all events are synthesized by the
+ // test environment.
+ static bool ShouldIgnoreNativePlatformEvents();
+
+ // Sets whether to ignore platform events and drop them or to forward them to
+ // the rest of the input pipeline.
+ static void SetIgnoreNativePlatformEvents(bool ignore_events);
+
// Adds a dispatcher to the dispatcher list. If a dispatcher is added during
// dispatching an event, then the newly added dispatcher also receives that
// event.
@@ -106,6 +116,8 @@ class EVENTS_EXPORT PlatformEventSource {
// reset and a previous override-dispatcher has been restored.
bool overridden_dispatcher_restored_;
+ static bool ignore_native_platform_events_;
+
PlatformEventObserverList observers_;
DISALLOW_COPY_AND_ASSIGN(PlatformEventSource);
diff --git a/chromium/ui/events/platform/platform_event_source_unittest.cc b/chromium/ui/events/platform/platform_event_source_unittest.cc
index d9a069e42cb..8dba043bb9e 100644
--- a/chromium/ui/events/platform/platform_event_source_unittest.cc
+++ b/chromium/ui/events/platform/platform_event_source_unittest.cc
@@ -12,10 +12,10 @@
#include <vector>
#include "base/bind.h"
-#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/platform/platform_event_dispatcher.h"
@@ -185,8 +185,8 @@ TEST_F(PlatformEventTest, DispatcherOrder) {
}
std::unique_ptr<PlatformEvent> event = CreatePlatformEvent();
source()->Dispatch(*event);
- ASSERT_EQ(arraysize(sequence), list_dispatcher.size());
- EXPECT_EQ(std::vector<int>(sequence, sequence + arraysize(sequence)),
+ ASSERT_EQ(base::size(sequence), list_dispatcher.size());
+ EXPECT_EQ(std::vector<int>(sequence, sequence + base::size(sequence)),
list_dispatcher);
}
@@ -243,8 +243,8 @@ TEST_F(PlatformEventTest, ObserverOrder) {
}
std::unique_ptr<PlatformEvent> event = CreatePlatformEvent();
source()->Dispatch(*event);
- ASSERT_EQ(arraysize(sequence), list_observer.size());
- EXPECT_EQ(std::vector<int>(sequence, sequence + arraysize(sequence)),
+ ASSERT_EQ(base::size(sequence), list_observer.size());
+ EXPECT_EQ(std::vector<int>(sequence, sequence + base::size(sequence)),
list_observer);
}
@@ -258,7 +258,7 @@ TEST_F(PlatformEventTest, DispatcherAndObserverOrder) {
std::unique_ptr<PlatformEvent> event = CreatePlatformEvent();
source()->Dispatch(*event);
const int expected[] = {10, 20, 12, 23};
- EXPECT_EQ(std::vector<int>(expected, expected + arraysize(expected)), list);
+ EXPECT_EQ(std::vector<int>(expected, expected + base::size(expected)), list);
}
// Tests that an overridden dispatcher receives events before the default
diff --git a/chromium/ui/events/win/keyboard_hook_win_base.cc b/chromium/ui/events/win/keyboard_hook_win_base.cc
index 1841b06dcf9..dbf5545cdef 100644
--- a/chromium/ui/events/win/keyboard_hook_win_base.cc
+++ b/chromium/ui/events/win/keyboard_hook_win_base.cc
@@ -15,7 +15,6 @@ KeyboardHookWinBase::KeyboardHookWinBase(
KeyboardHookWinBase::~KeyboardHookWinBase() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
if (!enable_hook_registration_)
return;
diff --git a/chromium/ui/events/win/media_keyboard_hook_win_unittest.cc b/chromium/ui/events/win/media_keyboard_hook_win_unittest.cc
index d0438771a84..1d65ccb9233 100644
--- a/chromium/ui/events/win/media_keyboard_hook_win_unittest.cc
+++ b/chromium/ui/events/win/media_keyboard_hook_win_unittest.cc
@@ -92,6 +92,7 @@ void MediaKeyboardHookWinTest::SendMediaKeyUpEvent(KeyboardCode key_code,
next_time_stamp()));
}
+namespace {
void VerifyKeyEvent(KeyEvent* key_event,
KeyboardCode non_located_key_code,
DomCode dom_code,
@@ -107,6 +108,7 @@ void VerifyKeyEvent(KeyEvent* key_event,
ASSERT_EQ(key_event->key_code(), non_located_key_code);
ASSERT_EQ(key_event->code(), dom_code);
}
+} // namespace
TEST_F(MediaKeyboardHookWinTest, SimpleKeypressTest) {
const KeyboardCode key_code = KeyboardCode::VKEY_MEDIA_PLAY_PAUSE;
diff --git a/chromium/ui/events/win/modifier_keyboard_hook_win_unittest.cc b/chromium/ui/events/win/modifier_keyboard_hook_win_unittest.cc
index ff1dcf4a1da..71bd3f0c2ef 100644
--- a/chromium/ui/events/win/modifier_keyboard_hook_win_unittest.cc
+++ b/chromium/ui/events/win/modifier_keyboard_hook_win_unittest.cc
@@ -101,6 +101,7 @@ void ModifierKeyboardHookWinTest::SendModifierKeyUpEvent(KeyboardCode key_code,
next_time_stamp()));
}
+namespace {
void VerifyKeyEvent(KeyEvent* key_event,
KeyboardCode non_located_key_code,
DomCode dom_code,
@@ -116,6 +117,7 @@ void VerifyKeyEvent(KeyEvent* key_event,
ASSERT_EQ(key_event->key_code(), non_located_key_code);
ASSERT_EQ(key_event->code(), dom_code);
}
+} // namespace
TEST_F(ModifierKeyboardHookWinTest, SimpleLeftControlKeypressTest) {
const KeyboardCode key_code = KeyboardCode::VKEY_LCONTROL;
diff --git a/chromium/ui/events/x/events_x.cc b/chromium/ui/events/x/events_x.cc
index b8df7b02091..36ed8f1ec90 100644
--- a/chromium/ui/events/x/events_x.cc
+++ b/chromium/ui/events/x/events_x.cc
@@ -8,8 +8,8 @@
#include <string.h>
#include <cmath>
-#include "base/macros.h"
#include "base/memory/singleton.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
@@ -45,7 +45,7 @@ unsigned int UpdateX11EventFlags(int ui_flags, unsigned int old_x_flags) {
{ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask},
};
unsigned int new_x_flags = old_x_flags;
- for (size_t i = 0; i < arraysize(flags); ++i) {
+ for (size_t i = 0; i < base::size(flags); ++i) {
if (ui_flags & flags[i].ui)
new_x_flags |= flags[i].x;
else
diff --git a/chromium/ui/events/x/events_x_unittest.cc b/chromium/ui/events/x/events_x_unittest.cc
index 897c5c5cb94..bc2eeace99d 100644
--- a/chromium/ui/events/x/events_x_unittest.cc
+++ b/chromium/ui/events/x/events_x_unittest.cc
@@ -10,7 +10,7 @@
#include <set>
#include <utility>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/test/simple_test_tick_clock.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -496,7 +496,7 @@ TEST_F(EventsXTest, ImeFabricatedKeyEvents) {
unsigned int state_to_be_fabricated[] = {
0, ShiftMask, LockMask, ShiftMask | LockMask,
};
- for (size_t i = 0; i < arraysize(state_to_be_fabricated); ++i) {
+ for (size_t i = 0; i < base::size(state_to_be_fabricated); ++i) {
unsigned int state = state_to_be_fabricated[i];
for (int is_char = 0; is_char < 2; ++is_char) {
XEvent x_event;
@@ -513,7 +513,7 @@ TEST_F(EventsXTest, ImeFabricatedKeyEvents) {
unsigned int state_to_be_not_fabricated[] = {
ControlMask, Mod1Mask, Mod2Mask, ShiftMask | ControlMask,
};
- for (size_t i = 0; i < arraysize(state_to_be_not_fabricated); ++i) {
+ for (size_t i = 0; i < base::size(state_to_be_not_fabricated); ++i) {
unsigned int state = state_to_be_not_fabricated[i];
for (int is_char = 0; is_char < 2; ++is_char) {
XEvent x_event;
diff --git a/chromium/ui/file_manager/BUILD.gn b/chromium/ui/file_manager/BUILD.gn
index 97493014ffa..a0c3ecdeee5 100644
--- a/chromium/ui/file_manager/BUILD.gn
+++ b/chromium/ui/file_manager/BUILD.gn
@@ -59,6 +59,7 @@ group("unit_test_data") {
"base/js:unit_tests",
"file_manager/background/js:unit_tests",
"file_manager/common/js:unit_tests",
+ "file_manager/foreground/elements:unit_tests",
"file_manager/foreground/js:unit_tests",
"file_manager/foreground/js/metadata:unit_tests",
"file_manager/foreground/js/ui:unit_tests",
diff --git a/chromium/ui/file_manager/audio_player/js/BUILD.gn b/chromium/ui/file_manager/audio_player/js/BUILD.gn
index ddf897af313..5d9d85a78c7 100644
--- a/chromium/ui/file_manager/audio_player/js/BUILD.gn
+++ b/chromium/ui/file_manager/audio_player/js/BUILD.gn
@@ -18,6 +18,7 @@ js_library("closure_compile_externs") {
sources = []
externs_list = [
"$externs_path/chrome_extensions.js",
+ "$externs_path/mediasession.js",
"../../externs/audio_player_foreground.js",
"../../externs/platform.js",
]
@@ -28,6 +29,7 @@ js_library("audio_player") {
"../elements:audio_player",
"../elements:track_list",
"//ui/file_manager/base/js:filtered_volume_manager",
+ "//ui/file_manager/base/js:mediasession_types",
"//ui/file_manager/file_manager/common/js:util",
"//ui/file_manager/file_manager/foreground/js/metadata:content_metadata_provider",
"//ui/file_manager/file_manager/foreground/js/metadata:metadata_model",
diff --git a/chromium/ui/file_manager/base/js/BUILD.gn b/chromium/ui/file_manager/base/js/BUILD.gn
index 2103bf75b51..607ba927cab 100644
--- a/chromium/ui/file_manager/base/js/BUILD.gn
+++ b/chromium/ui/file_manager/base/js/BUILD.gn
@@ -78,3 +78,6 @@ js_unit_tests("unit_tests") {
":volume_manager_types_unittest",
]
}
+
+js_library("mediasession_types") {
+}
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 4732f285269..189b3b217f5 100644
--- a/chromium/ui/file_manager/file_manager/background/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -66,6 +66,7 @@ js_type_check("closure_compile_module") {
js_type_check("test_support_type_check") {
testonly = true
deps = [
+ ":mock_crostini",
":mock_drive_sync_handler",
":mock_file_operation_manager",
":mock_media_scanner",
@@ -79,12 +80,14 @@ js_library("closure_compile_externs") {
sources = []
externs_list = [
"$externs_path/metrics_private.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_runner.js",
+ "../../../externs/background/media_import_handler.js",
"../../../externs/background/media_scanner.js",
"../../../externs/background/progress_center.js",
"../../../externs/background_window.js",
@@ -146,12 +149,23 @@ js_library("crostini") {
"//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/externs:volume_manager",
]
+ externs_list = [ "//ui/file_manager/externs/background/crostini.js" ]
}
-js_unittest("crostini_unittest") {
+js_library("mock_crostini") {
+ testonly = true
deps = [
":crostini",
- "../../common/js:mock_entry",
+ ]
+ externs_list = [ "//ui/file_manager/externs/background/crostini.js" ]
+ visibility = []
+ visibility = [ "//ui/file_manager/file_manager/*" ]
+}
+
+js_unittest("crostini_unittest") {
+ deps = [
+ ":mock_crostini",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
"//ui/webui/resources/js:webui_resource_test",
]
}
@@ -182,6 +196,8 @@ js_library("mock_drive_sync_handler") {
"//ui/webui/resources/js/cr:event_target",
]
externs_list = [ "../../../externs/background/drive_sync_handler.js" ]
+ visibility = []
+ visibility = [ "//ui/file_manager/file_manager/*" ]
}
js_library("drive_sync_handler") {
@@ -234,7 +250,15 @@ js_library("file_operation_handler") {
deps = [
":file_operation_manager",
":progress_center",
- "../../common/js:progress_center_common",
+ ]
+}
+
+js_unittest("file_operation_handler_unittest") {
+ deps = [
+ ":file_operation_handler",
+ ":mock_file_operation_manager",
+ ":mock_progress_center",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -326,6 +350,22 @@ js_library("media_import_handler") {
"../../common/js:importer_common",
"../../common/js:metrics",
]
+ externs_list = [ "//ui/file_manager/externs/background/import_runner.js" ]
+}
+
+js_unittest("media_import_handler_unittest") {
+ deps = [
+ ":media_import_handler",
+ ":mock_drive_sync_handler",
+ ":mock_media_scanner",
+ ":mock_progress_center",
+ ":mock_volume_manager",
+ ":test_import_history",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ]
}
js_library("mock_media_scanner") {
@@ -335,6 +375,8 @@ js_library("mock_media_scanner") {
":test_import_history",
]
externs_list = [ "../../../externs/background/media_scanner.js" ]
+ visibility = []
+ visibility = [ "//ui/file_manager/file_manager/*" ]
}
js_library("media_scanner") {
@@ -360,7 +402,7 @@ js_library("mock_volume_manager") {
":volume_info_list_impl",
":volume_manager_factory",
":volume_manager_impl",
- "../../common/js:mock_entry",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
]
}
@@ -488,8 +530,10 @@ js_unit_tests("unit_tests") {
":device_handler_unittest",
":drive_sync_handler_unittest",
":duplicate_finder_unittest",
+ ":file_operation_handler_unittest",
":file_operation_manager_unittest",
":import_history_unittest",
+ ":media_import_handler_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 6b93293fada..31581662ecb 100644
--- a/chromium/ui/file_manager/file_manager/common/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/common/js/BUILD.gn
@@ -75,6 +75,14 @@ js_library("file_type") {
]
}
+js_unittest("file_type_unittest") {
+ deps = [
+ ":file_type",
+ ":mock_entry",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
# These importer files actually belong here. Nothing outside the Files app uses
# them, so restrict visibility. TODO(tapted): Simplify visibility when
# everything else moves to //ui/file_manager/base.
@@ -174,6 +182,7 @@ js_library("util") {
"../../../externs/app_window_common.js",
"../../../externs/entry_location.js",
"../../../externs/platform.js",
+ "../../../externs/volume_info.js",
]
}
@@ -190,6 +199,7 @@ js_unittest("util_unittest") {
js_unit_tests("unit_tests") {
deps = [
":async_util_unittest",
+ ":file_type_unittest",
":files_app_entry_types_unittest",
":importer_common_unittest",
":lru_cache_unittest",
diff --git a/chromium/ui/file_manager/file_manager/foreground/elements/BUILD.gn b/chromium/ui/file_manager/file_manager/foreground/elements/BUILD.gn
index b1ecbbcb771..d8e8fbb11be 100644
--- a/chromium/ui/file_manager/file_manager/foreground/elements/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/foreground/elements/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 = [
":files_icon_button",
":files_metadata_box",
@@ -68,3 +78,16 @@ js_library("files_toggle_ripple") {
js_library("files_tooltip") {
visibility += [ "//ui/file_manager/gallery/*" ]
}
+
+js_unittest("files_tooltip_unittest") {
+ deps = [
+ ":files_tooltip",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
+js_unit_tests("unit_tests") {
+ deps = [
+ ":files_tooltip_unittest",
+ ]
+}
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 dfa0c48d7c9..d55d0cfd453 100644
--- a/chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -151,6 +151,17 @@ js_library("mock_actions_model") {
]
}
+js_unittest("actions_model_unittest") {
+ deps = [
+ ":actions_model",
+ "metadata:mock_metadata",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/background/js:mock_drive_sync_handler",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager",
+ ]
+}
+
js_library("mock_directory_model") {
testonly = true
deps = [
@@ -165,6 +176,7 @@ js_library("mock_folder_shortcut_data_model") {
testonly = true
deps = [
"//ui/file_manager/file_manager/common/js:mock_entry",
+ "//ui/webui/resources/js/cr/ui:array_data_model",
]
}
@@ -348,6 +360,7 @@ js_library("file_manager_commands") {
"ui:file_manager_ui",
"//ui/webui/resources/cr_elements/cr_input:cr_input",
]
+ externs_list = [ "//ui/file_manager/externs/command_handler_deps.js" ]
}
js_library("file_selection") {
@@ -367,10 +380,23 @@ js_library("file_selection") {
js_library("file_tasks") {
deps = [
":directory_model",
+ ":naming_controller",
":task_history",
"metadata:metadata_model",
"ui:file_manager_ui",
]
+ externs_list = [ "../../../externs/background/crostini.js" ]
+}
+
+js_unittest("file_tasks_unittest") {
+ deps = [
+ ":file_tasks",
+ "metadata:mock_metadata",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/background/js:mock_crostini",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ ]
}
js_library("file_transfer_controller") {
@@ -388,6 +414,7 @@ js_library("file_transfer_controller") {
"ui:multi_profile_share_dialog",
"ui:progress_center_panel",
]
+ externs_list = [ "../../../externs/background/progress_center.js" ]
}
js_library("file_watcher") {
@@ -406,6 +433,7 @@ js_library("folder_shortcuts_data_model") {
"//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/webui/resources/js/cr:event_target",
]
}
@@ -434,6 +462,22 @@ js_library("import_controller") {
"ui:directory_tree",
"ui:file_manager_ui",
]
+ externs_list = [
+ "//ui/file_manager/externs/background/import_runner.js",
+ "//ui/file_manager/externs/background/media_import_handler.js",
+ "//ui/file_manager/externs/command_handler_deps.js",
+ ]
+}
+
+js_unittest("import_controller_unittest") {
+ deps = [
+ ":import_controller",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/background/js:mock_media_scanner",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager",
+ "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ]
}
js_library("last_modified_controller") {
@@ -460,6 +504,15 @@ js_library("list_thumbnail_loader") {
]
}
+js_unittest("list_thumbnail_loader_unittest") {
+ deps = [
+ ":list_thumbnail_loader",
+ ":mock_thumbnail_loader",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ ]
+}
+
js_library("main") {
deps = [
":file_manager",
@@ -526,6 +579,17 @@ js_library("navigation_list_model") {
]
}
+js_unittest("navigation_list_model_unittest") {
+ deps = [
+ ":mock_directory_model",
+ ":mock_folder_shortcut_data_model",
+ ":navigation_list_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",
+ ]
+}
+
js_library("progress_center_item_group") {
deps = [
"../../common/js:progress_center_common",
@@ -533,6 +597,13 @@ js_library("progress_center_item_group") {
]
}
+js_unittest("progress_center_item_group_unittest") {
+ deps = [
+ ":progress_center_item_group",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
js_library("providers_model") {
deps = [
"//ui/webui/resources/js:assert",
@@ -641,6 +712,17 @@ js_library("task_controller") {
]
}
+js_unittest("task_controller_unittest") {
+ deps = [
+ ":task_controller",
+ "metadata:mock_metadata",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/background/js:mock_crostini",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ ]
+}
+
js_library("task_history") {
deps = [
"//ui/webui/resources/js/cr:event_target",
@@ -691,9 +773,16 @@ js_library("webui_command_extender") {
js_unit_tests("unit_tests") {
deps = [
+ ":actions_model_unittest",
":file_list_model_unittest",
+ ":file_tasks_unittest",
+ ":import_controller_unittest",
+ ":list_thumbnail_loader_unittest",
+ ":navigation_list_model_unittest",
+ ":progress_center_item_group_unittest",
":providers_model_unittest",
":spinner_controller_unittest",
+ ":task_controller_unittest",
":thumbnail_loader_unittest",
]
}
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 484fd968bc2..6f95c187a4b 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
@@ -8,6 +8,14 @@ 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",
+ ":unit_tests_type_check",
+ ]
+}
+
js_type_check("closure_compile_module") {
deps = [
":byte_reader",
@@ -55,6 +63,13 @@ js_library("content_metadata_provider") {
]
}
+js_unittest("content_metadata_provider_unittest") {
+ deps = [
+ ":content_metadata_provider",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
js_library("exif_constants") {
}
@@ -62,14 +77,30 @@ js_library("exif_parser") {
deps = [
":exif_constants",
":image_parsers",
- ":metadata_parser",
]
externs_list = [ "../../../../externs/exif_entry.js" ]
}
+js_unittest("exif_parser_unittest") {
+ deps = [
+ ":exif_parser",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/gallery/js/image_editor:exif_encoder",
+ ]
+}
+
js_library("external_metadata_provider") {
deps = [
":metadata_provider",
+ "//ui/file_manager/externs:file_manager_private",
+ ]
+}
+
+js_unittest("external_metadata_provider_unittest") {
+ deps = [
+ ":external_metadata_provider",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -79,6 +110,13 @@ js_library("file_system_metadata_provider") {
]
}
+js_unittest("file_system_metadata_provider_unittest") {
+ deps = [
+ ":file_system_metadata_provider",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
js_library("function_parallel") {
deps = [
":metadata_parser",
@@ -142,6 +180,13 @@ js_library("metadata_cache_set") {
]
}
+js_unittest("metadata_cache_set_unittest") {
+ deps = [
+ ":metadata_cache_set",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
js_library("metadata_dispatcher") {
deps = [
":metadata_parser",
@@ -165,6 +210,13 @@ js_library("metadata_model") {
]
}
+js_unittest("metadata_model_unittest") {
+ deps = [
+ ":metadata_model",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
js_library("metadata_parser") {
deps = [
":byte_reader",
@@ -204,6 +256,13 @@ js_library("multi_metadata_provider") {
]
}
+js_unittest("multi_metadata_provider_unittest") {
+ deps = [
+ ":multi_metadata_provider",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
js_library("thumbnail_model") {
deps = [
":metadata_model",
@@ -220,16 +279,15 @@ js_unittest("thumbnail_model_unittest") {
js_unit_tests("unit_tests") {
deps = [
+ ":content_metadata_provider_unittest",
+ ":exif_parser_unittest",
+ ":external_metadata_provider_unittest",
+ ":file_system_metadata_provider_unittest",
":image_orientation_unittest",
":metadata_cache_item_unittest",
+ ":metadata_cache_set_unittest",
+ ":metadata_model_unittest",
+ ":multi_metadata_provider_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 c3cac1513c0..a943c32272a 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
@@ -44,6 +44,7 @@ js_type_check("closure_compile_module") {
":install_linux_package_dialog",
":list_container",
":location_line",
+ ":multi_menu",
":multi_profile_share_dialog",
":progress_center_panel",
":providers_menu",
@@ -101,6 +102,7 @@ js_library("banners") {
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js/cr:event_target",
]
+ externs_list = [ "../../../../externs/chrome_echo_private.js" ]
}
js_library("combobutton") {
@@ -109,6 +111,7 @@ js_library("combobutton") {
"../../elements:files_toggle_ripple",
"//ui/webui/resources/js/cr/ui:menu_button",
]
+ externs_list = [ "../../../../externs/paper_elements.js" ]
}
js_library("commandbutton") {
@@ -152,6 +155,18 @@ js_library("directory_tree") {
]
}
+js_unittest("directory_tree_unittest") {
+ deps = [
+ ":directory_tree",
+ "//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/file_manager/file_manager/foreground/js:mock_directory_model",
+ "//ui/file_manager/file_manager/foreground/js:mock_folder_shortcut_data_model",
+ "//ui/file_manager/file_manager/foreground/js:mock_navigation_list_model",
+ ]
+}
+
js_library("drag_selector") {
deps = [
"//ui/webui/resources/js/cr:ui",
@@ -227,6 +242,7 @@ js_library("file_manager_ui") {
":install_linux_package_dialog",
":list_container",
":location_line",
+ ":multi_menu",
":multi_profile_share_dialog",
":progress_center_panel",
":providers_menu",
@@ -238,7 +254,6 @@ js_library("file_manager_ui") {
"//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",
"//ui/webui/resources/js/cr/ui:dialogs",
@@ -321,6 +336,7 @@ js_library("files_menu") {
"//ui/webui/resources/js/cr/ui:menu",
"//ui/webui/resources/js/cr/ui:menu_item",
]
+ externs_list = [ "../../../../externs/paper_elements.js" ]
}
js_library("install_linux_package_dialog") {
@@ -343,6 +359,17 @@ js_library("list_container") {
]
}
+js_unittest("list_container_unittest") {
+ deps = [
+ ":list_container",
+ "../../../common/js:util",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/webui/resources/js:webui_resource_test",
+ "//ui/webui/resources/js/cr/ui:context_menu_handler",
+ "//ui/webui/resources/js/cr/ui:menu",
+ ]
+}
+
js_library("location_line") {
deps = [
"../../../common/js:files_app_entry_types",
@@ -353,6 +380,25 @@ js_library("location_line") {
]
}
+js_library("multi_menu") {
+ deps = [
+ "//ui/webui/resources/js:event_tracker",
+ "//ui/webui/resources/js/cr/ui:menu",
+ "//ui/webui/resources/js/cr/ui:menu_button",
+ "//ui/webui/resources/js/cr/ui:menu_item",
+ "//ui/webui/resources/js/cr/ui:position_util",
+ ]
+}
+
+js_unittest("multi_menu_unittest") {
+ deps = [
+ ":multi_menu",
+ "../../../common/js:util",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("multi_profile_share_dialog") {
deps = [
":file_manager_dialog_base",
@@ -378,6 +424,7 @@ js_library("providers_menu") {
"//ui/webui/resources/js/cr/ui:menu",
"//ui/webui/resources/js/cr/ui:position_util",
]
+ externs_list = [ "../../../../externs/menu_item_update_event.js" ]
}
js_library("search_box") {
@@ -392,6 +439,7 @@ js_library("search_box") {
"//ui/webui/resources/js/cr:ui",
"//ui/webui/resources/js/cr/ui:autocomplete_list",
]
+ externs_list = [ "../../../../externs/search_item.js" ]
}
js_library("suggest_apps_dialog") {
@@ -406,13 +454,17 @@ js_library("suggest_apps_dialog") {
"../../../cws_widget:cws_widget_container",
"//ui/file_manager/base/js:volume_manager_types",
]
+ externs_list = [ "../../../../externs/chrome_webstore_widget_private.js" ]
}
js_unit_tests("unit_tests") {
deps = [
":actions_submenu_unittest",
+ ":directory_tree_unittest",
":file_list_selection_model_unittest",
":file_table_unittest",
":file_tap_handler_unittest",
+ ":list_container_unittest",
+ ":multi_menu_unittest",
]
}
diff --git a/chromium/ui/file_manager/file_manager/test/BUILD.gn b/chromium/ui/file_manager/file_manager/test/BUILD.gn
index 6f5cffa33e3..965a6843c40 100644
--- a/chromium/ui/file_manager/file_manager/test/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/test/BUILD.gn
@@ -25,6 +25,7 @@ action("create_test_main") {
"crostini_share.js",
"crostini_tasks.js",
"js/strings.js",
+ "menu.js",
"progress_center.js",
"uma.js",
]
@@ -41,6 +42,7 @@ js_type_check("closure_compile") {
":crostini_mount",
":crostini_share",
":crostini_tasks",
+ ":menu",
":progress_center",
":uma",
]
@@ -94,6 +96,13 @@ js_library("crostini_tasks") {
]
}
+js_library("menu") {
+ deps = [
+ "js:test_util",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("progress_center") {
deps = [
"js:test_util",
diff --git a/chromium/ui/file_manager/video_player/js/BUILD.gn b/chromium/ui/file_manager/video_player/js/BUILD.gn
index 23e98f8768f..1090e8ac720 100644
--- a/chromium/ui/file_manager/video_player/js/BUILD.gn
+++ b/chromium/ui/file_manager/video_player/js/BUILD.gn
@@ -22,6 +22,7 @@ js_library("closure_compile_externs") {
"$externs_path/chrome_extensions.js",
"$externs_path/media_player_private.js",
"$externs_path/metrics_private.js",
+ "$externs_path/mediasession.js",
"../../externs/chrome_cast.js",
"../../externs/platform.js",
]
@@ -41,7 +42,7 @@ js_library("error_util") {
js_library("media_controls") {
deps = [
"../../file_manager/common/js:util",
- "//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/cr/ui:menu_button",
]
}
@@ -49,15 +50,20 @@ js_library("media_controls") {
js_library("mouse_inactivity_watcher") {
}
+js_library("video_player_native_controls") {
+}
+
js_library("video_player") {
deps = [
":error_util",
":media_controls",
":mouse_inactivity_watcher",
":video_player_metrics",
+ ":video_player_native_controls",
"cast:cast_video_element",
"cast:media_manager",
"//ui/file_manager/base/js:filtered_volume_manager",
+ "//ui/file_manager/base/js:mediasession_types",
"//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",
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 02cddc535b2..7305df109ef 100644
--- a/chromium/ui/file_manager/video_player/js/cast/BUILD.gn
+++ b/chromium/ui/file_manager/video_player/js/cast/BUILD.gn
@@ -19,6 +19,7 @@ js_library("closure_compile_externs") {
externs_list = [
"$externs_path/chrome_extensions.js",
"$externs_path/media_player_private.js",
+ "$externs_path/mediasession.js",
"../../../externs/app_window_common.js",
"../../../externs/background/volume_manager_factory.js",
"../../../externs/chrome_cast.js",
diff --git a/chromium/ui/gfx/BUILD.gn b/chromium/ui/gfx/BUILD.gn
index d0dbfa2c6d5..b930ab44ff3 100644
--- a/chromium/ui/gfx/BUILD.gn
+++ b/chromium/ui/gfx/BUILD.gn
@@ -5,8 +5,8 @@
import("//build/config/jumbo.gni")
import("//build/config/ui.gni")
import("//device/vr/buildflags/buildflags.gni")
-import("//testing/test.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
+import("//testing/test.gni")
if (is_android) {
import("//build/config/android/config.gni")
@@ -26,6 +26,8 @@ source_set("gfx_export") {
jumbo_component("geometry_skia") {
sources = [
"geometry_skia_export.h",
+ "rrect_f.cc",
+ "rrect_f.h",
"skia_util.cc",
"skia_util.h",
"transform.cc",
@@ -36,7 +38,6 @@ jumbo_component("geometry_skia") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
"//base",
- "//gpu/vulkan:buildflags",
"//skia",
"//ui/gfx/geometry",
]
@@ -126,8 +127,6 @@ jumbo_component("gfx") {
"mac/scoped_cocoa_disable_screen_updates.mm",
"nine_image_painter.cc",
"nine_image_painter.h",
- "path.cc",
- "path.h",
"path_mac.h",
"path_mac.mm",
"path_win.cc",
@@ -181,6 +180,8 @@ jumbo_component("gfx") {
"win/scoped_set_map_mode.h",
"win/singleton_hwnd.cc",
"win/singleton_hwnd.h",
+ "win/singleton_hwnd_hot_key_observer.cc",
+ "win/singleton_hwnd_hot_key_observer.h",
"win/singleton_hwnd_observer.cc",
"win/singleton_hwnd_observer.h",
"win/text_analysis_source.cc",
@@ -227,9 +228,7 @@ jumbo_component("gfx") {
configs += [
"//build/config:precompiled_headers",
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- "//build/config/compiler:no_size_t_to_int_warning",
+ "//build/config/compiler:noshadowing",
"//build/config/compiler:wexit_time_destructors",
]
@@ -616,6 +615,7 @@ test("gfx_unittests") {
"image/image_unittest.cc",
"ios/NSString+CrStringDrawing_unittest.mm",
"ios/uikit_util_unittest.mm",
+ "rrect_f_unittest.cc",
"test/run_all_unittests.cc",
"text_elider_unittest.cc",
"text_utils_unittest.cc",
@@ -692,9 +692,6 @@ test("gfx_unittests") {
sources += [ "paint_vector_icon_unittest.cc" ]
}
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
deps = [
":gfx",
":test_support",
diff --git a/chromium/ui/gfx/DEPS b/chromium/ui/gfx/DEPS
index 3a287d9d617..1fa634730b4 100644
--- a/chromium/ui/gfx/DEPS
+++ b/chromium/ui/gfx/DEPS
@@ -3,11 +3,9 @@ include_rules = [
"+cc/base",
"+cc/paint",
"+device/vr/buildflags/buildflags.h",
- "+gpu/vulkan/buildflags.h",
"+skia/ext",
"+third_party/harfbuzz-ng",
"+third_party/skia",
- "+third_party/vulkan",
"+ui/ios",
"-testing/gmock",
diff --git a/chromium/ui/gfx/OWNERS b/chromium/ui/gfx/OWNERS
index a146a9e20bb..a9f98f4bda5 100644
--- a/chromium/ui/gfx/OWNERS
+++ b/chromium/ui/gfx/OWNERS
@@ -4,6 +4,10 @@ asvitkine@chromium.org
# RenderText and related classes.
msw@chromium.org
+# Color utils.
+per-file color_palette.h=pkasting@chromium.org
+per-file color_utils*=pkasting@chromium.org
+
# Display and related classes.
per-file display*=oshima@chromium.org
per-file screen*=oshima@chromium.org
diff --git a/chromium/ui/gfx/animation/animation.cc b/chromium/ui/gfx/animation/animation.cc
index 90342df9b79..c651217fc66 100644
--- a/chromium/ui/gfx/animation/animation.cc
+++ b/chromium/ui/gfx/animation/animation.cc
@@ -113,6 +113,12 @@ bool Animation::ScrollAnimationsEnabledBySystem() {
// Defined in platform specific files for Windows and OSX.
return true;
}
+
+bool Animation::PrefersReducedMotion() {
+ // By default, we assume that animations are enabled, to avoid impacting the
+ // experience for users on systems that don't have APIs for reduced motion.
+ return false;
+}
#endif
bool Animation::ShouldSendCanceledFromStop() {
diff --git a/chromium/ui/gfx/animation/animation.h b/chromium/ui/gfx/animation/animation.h
index bb826e2bde0..c2062a14488 100644
--- a/chromium/ui/gfx/animation/animation.h
+++ b/chromium/ui/gfx/animation/animation.h
@@ -79,6 +79,10 @@ class ANIMATION_EXPORT Animation : public AnimationContainerElement {
// process.
static bool ScrollAnimationsEnabledBySystem();
+ // Determines whether the user desires reduced motion based on platform APIs.
+ // Should only be called from the browser process.
+ static bool PrefersReducedMotion();
+
protected:
// Invoked from Start to allow subclasses to prepare for the animation.
virtual void AnimationStarted() {}
diff --git a/chromium/ui/gfx/animation/animation_mac.mm b/chromium/ui/gfx/animation/animation_mac.mm
index 99a841c4b16..814c406f0b9 100644
--- a/chromium/ui/gfx/animation/animation_mac.mm
+++ b/chromium/ui/gfx/animation/animation_mac.mm
@@ -4,11 +4,16 @@
#include "ui/gfx/animation/animation.h"
-#import <Foundation/Foundation.h>
+#import <Cocoa/Cocoa.h>
#include "base/mac/mac_util.h"
#include "base/message_loop/message_loop.h"
+// Only available since 10.12.
+@interface NSWorkspace (AvailableSinceSierra)
+@property(readonly) BOOL accessibilityDisplayShouldReduceMotion;
+@end
+
namespace gfx {
// static
@@ -27,4 +32,22 @@ bool Animation::ScrollAnimationsEnabledBySystem() {
return enabled;
}
+// static
+bool Animation::PrefersReducedMotion() {
+ // Because of sandboxing, OS settings should only be queried from the browser
+ // process.
+ DCHECK(base::MessageLoopCurrentForUI::IsSet() ||
+ base::MessageLoopCurrentForIO::IsSet());
+
+ // We default to assuming that animations are enabled, to avoid impacting the
+ // experience for users on pre-10.12 systems.
+ bool prefers_reduced_motion = false;
+ SEL sel = @selector(accessibilityDisplayShouldReduceMotion);
+ if ([[NSWorkspace sharedWorkspace] respondsToSelector:sel]) {
+ prefers_reduced_motion =
+ [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion];
+ }
+ return prefers_reduced_motion;
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/animation/animation_win.cc b/chromium/ui/gfx/animation/animation_win.cc
index 90b64af80ee..d7627addcb0 100644
--- a/chromium/ui/gfx/animation/animation_win.cc
+++ b/chromium/ui/gfx/animation/animation_win.cc
@@ -23,4 +23,13 @@ bool Animation::ScrollAnimationsEnabledBySystem() {
return ShouldRenderRichAnimation();
}
+// static
+bool Animation::PrefersReducedMotion() {
+ // We default to assuming that animations are enabled, to avoid impacting the
+ // experience for users on systems that don't have SPI_GETCLIENTAREAANIMATION.
+ BOOL win_anim_enabled = true;
+ SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &win_anim_enabled, 0);
+ return !win_anim_enabled;
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/animation/slide_animation.cc b/chromium/ui/gfx/animation/slide_animation.cc
index ccdc22783e9..27c4257f658 100644
--- a/chromium/ui/gfx/animation/slide_animation.cc
+++ b/chromium/ui/gfx/animation/slide_animation.cc
@@ -6,6 +6,8 @@
#include <math.h>
+#include "ui/gfx/animation/animation_delegate.h"
+
namespace gfx {
// How long animations should take by default.
@@ -46,6 +48,10 @@ void SlideAnimation::Show() {
// Make sure we actually have something to do.
if (slide_duration_ == 0) {
AnimateToState(1.0); // Skip to the end of the animation.
+ if (delegate()) {
+ delegate()->AnimationProgressed(this);
+ delegate()->AnimationEnded(this);
+ }
return;
} else if (value_current_ == value_end_) {
return;
@@ -70,6 +76,10 @@ void SlideAnimation::Hide() {
// TODO(bruthig): Investigate if this should really be animating to 0.0, I
// think it should be animating to 1.0.
AnimateToState(0.0); // Skip to the end of the animation.
+ if (delegate()) {
+ delegate()->AnimationProgressed(this);
+ delegate()->AnimationEnded(this);
+ }
return;
} else if (value_current_ == value_end_) {
return;
diff --git a/chromium/ui/gfx/break_list_unittest.cc b/chromium/ui/gfx/break_list_unittest.cc
index e84d80ef1c5..84aec179b14 100644
--- a/chromium/ui/gfx/break_list_unittest.cc
+++ b/chromium/ui/gfx/break_list_unittest.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/range/range.h"
@@ -158,8 +158,7 @@ TEST_F(BreakListTest, GetBreakAndRange) {
{ 9, 4, Range(6, 8) },
};
-
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
BreakList<bool>::const_iterator it = breaks.GetBreak(cases[i].position);
EXPECT_EQ(breaks.breaks()[cases[i].break_index], *it);
EXPECT_EQ(breaks.GetRange(it), cases[i].range);
diff --git a/chromium/ui/gfx/buffer_format_util.cc b/chromium/ui/gfx/buffer_format_util.cc
index 5e3de26ae3f..22326d53e43 100644
--- a/chromium/ui/gfx/buffer_format_util.cc
+++ b/chromium/ui/gfx/buffer_format_util.cc
@@ -5,8 +5,8 @@
#include "ui/gfx/buffer_format_util.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/numerics/safe_math.h"
+#include "base/stl_util.h"
namespace gfx {
namespace {
@@ -21,11 +21,10 @@ const BufferFormat kBufferFormats[] = {
BufferFormat::UYVY_422, BufferFormat::YUV_420_BIPLANAR,
BufferFormat::YVU_420};
-static_assert(arraysize(kBufferFormats) ==
+static_assert(base::size(kBufferFormats) ==
(static_cast<int>(BufferFormat::LAST) + 1),
"BufferFormat::LAST must be last value of kBufferFormats");
-
bool RowSizeForBufferFormatChecked(
size_t width, BufferFormat format, size_t plane, size_t* size_in_bytes) {
base::CheckedNumeric<size_t> checked_size = width;
@@ -81,7 +80,7 @@ bool RowSizeForBufferFormatChecked(
std::vector<BufferFormat> GetBufferFormatsForTesting() {
return std::vector<BufferFormat>(kBufferFormats,
- kBufferFormats + arraysize(kBufferFormats));
+ kBufferFormats + base::size(kBufferFormats));
}
size_t NumberOfPlanesForBufferFormat(BufferFormat format) {
@@ -127,12 +126,12 @@ size_t SubsamplingFactorForBufferFormat(BufferFormat format, size_t plane) {
return 1;
case BufferFormat::YVU_420: {
static size_t factor[] = {1, 2, 2};
- DCHECK_LT(static_cast<size_t>(plane), arraysize(factor));
+ DCHECK_LT(static_cast<size_t>(plane), base::size(factor));
return factor[plane];
}
case BufferFormat::YUV_420_BIPLANAR: {
static size_t factor[] = {1, 2};
- DCHECK_LT(static_cast<size_t>(plane), arraysize(factor));
+ DCHECK_LT(static_cast<size_t>(plane), base::size(factor));
return factor[plane];
}
}
@@ -197,13 +196,13 @@ size_t BufferOffsetForBufferFormat(const Size& size,
return 0;
case BufferFormat::YVU_420: {
static size_t offset_in_2x2_sub_sampling_sizes[] = {0, 4, 5};
- DCHECK_LT(plane, arraysize(offset_in_2x2_sub_sampling_sizes));
+ DCHECK_LT(plane, base::size(offset_in_2x2_sub_sampling_sizes));
return offset_in_2x2_sub_sampling_sizes[plane] *
(size.width() / 2 + size.height() / 2);
}
case gfx::BufferFormat::YUV_420_BIPLANAR: {
static size_t offset_in_2x2_sub_sampling_sizes[] = {0, 4};
- DCHECK_LT(plane, arraysize(offset_in_2x2_sub_sampling_sizes));
+ DCHECK_LT(plane, base::size(offset_in_2x2_sub_sampling_sizes));
return offset_in_2x2_sub_sampling_sizes[plane] *
(size.width() / 2 + size.height() / 2);
}
diff --git a/chromium/ui/gfx/canvas.cc b/chromium/ui/gfx/canvas.cc
index 5cd71db6015..ab34572b8ed 100644
--- a/chromium/ui/gfx/canvas.cc
+++ b/chromium/ui/gfx/canvas.cc
@@ -140,12 +140,12 @@ void Canvas::Save() {
}
void Canvas::SaveLayerAlpha(uint8_t alpha) {
- canvas_->saveLayerAlpha(NULL, alpha, false);
+ canvas_->saveLayerAlpha(NULL, alpha);
}
void Canvas::SaveLayerAlpha(uint8_t alpha, const Rect& layer_bounds) {
SkRect bounds(RectToSkRect(layer_bounds));
- canvas_->saveLayerAlpha(&bounds, alpha, false);
+ canvas_->saveLayerAlpha(&bounds, alpha);
}
void Canvas::SaveLayerWithFlags(const cc::PaintFlags& flags) {
diff --git a/chromium/ui/gfx/canvas_skia.cc b/chromium/ui/gfx/canvas_skia.cc
index 3711f05dcdf..59b48db8888 100644
--- a/chromium/ui/gfx/canvas_skia.cc
+++ b/chromium/ui/gfx/canvas_skia.cc
@@ -88,8 +88,9 @@ void UpdateRenderText(const Rect& rect,
render_text->SetColor(color);
const int font_style = font_list.GetFontStyle();
- render_text->SetStyle(ITALIC, (font_style & Font::ITALIC) != 0);
- render_text->SetStyle(UNDERLINE, (font_style & Font::UNDERLINE) != 0);
+ render_text->SetStyle(TEXT_STYLE_ITALIC, (font_style & Font::ITALIC) != 0);
+ render_text->SetStyle(TEXT_STYLE_UNDERLINE,
+ (font_style & Font::UNDERLINE) != 0);
render_text->SetWeight(font_list.GetFontWeight());
}
@@ -198,7 +199,7 @@ void Canvas::DrawStringRectWithFlags(const base::string16& text,
rect.set_height(line_height - line_padding);
if (range.IsValid())
- render_text->ApplyStyle(UNDERLINE, true, range);
+ render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, range);
render_text->SetDisplayRect(rect);
render_text->Draw(this);
rect += Vector2d(0, line_height);
@@ -229,7 +230,7 @@ void Canvas::DrawStringRectWithFlags(const base::string16& text,
UpdateRenderText(rect, adjusted_text, font_list, flags, color,
render_text.get());
if (range.IsValid())
- render_text->ApplyStyle(UNDERLINE, true, range);
+ render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, range);
render_text->Draw(this);
}
diff --git a/chromium/ui/gfx/codec/chromeos/jpeg_codec_robust_slow_unittest.cc b/chromium/ui/gfx/codec/chromeos/jpeg_codec_robust_slow_unittest.cc
index 5304ab327d6..f857732d57b 100644
--- a/chromium/ui/gfx/codec/chromeos/jpeg_codec_robust_slow_unittest.cc
+++ b/chromium/ui/gfx/codec/chromeos/jpeg_codec_robust_slow_unittest.cc
@@ -5,7 +5,7 @@
#include <math.h>
#include <stdint.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h"
@@ -94,10 +94,10 @@ TEST(JPEGCodecRobustSlow, InvalidRead) {
std::vector<unsigned char> output;
int outw, outh;
ASSERT_TRUE(JPEGCodecRobustSlow::Decode(
- kTopSitesMigrationTestImage, arraysize(kTopSitesMigrationTestImage),
+ kTopSitesMigrationTestImage, base::size(kTopSitesMigrationTestImage),
JPEGCodecRobustSlow::FORMAT_RGB, &output, &outw, &outh));
ASSERT_TRUE(JPEGCodecRobustSlow::Decode(
- kTopSitesMigrationTestImage, arraysize(kTopSitesMigrationTestImage),
+ kTopSitesMigrationTestImage, base::size(kTopSitesMigrationTestImage),
JPEGCodecRobustSlow::FORMAT_RGBA, &output, &outw, &outh));
}
diff --git a/chromium/ui/gfx/codec/jpeg_codec_unittest.cc b/chromium/ui/gfx/codec/jpeg_codec_unittest.cc
index f97206af221..4b61921b217 100644
--- a/chromium/ui/gfx/codec/jpeg_codec_unittest.cc
+++ b/chromium/ui/gfx/codec/jpeg_codec_unittest.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/codec/jpeg_codec.h"
@@ -174,9 +174,8 @@ TEST(JPEGCodec, InvalidRead) {
std::vector<unsigned char> output;
int outw, outh;
JPEGCodec::Decode(kTopSitesMigrationTestImage,
- arraysize(kTopSitesMigrationTestImage),
- JPEGCodec::FORMAT_RGBA, &output,
- &outw, &outh);
+ base::size(kTopSitesMigrationTestImage),
+ JPEGCodec::FORMAT_RGBA, &output, &outw, &outh);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/codec/png_codec_unittest.cc b/chromium/ui/gfx/codec/png_codec_unittest.cc
index fee3e2a7577..260f7c9767a 100644
--- a/chromium/ui/gfx/codec/png_codec_unittest.cc
+++ b/chromium/ui/gfx/codec/png_codec_unittest.cc
@@ -9,7 +9,7 @@
#include <cmath>
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libpng/png.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -923,13 +923,13 @@ TEST(PNGCodec, EncodeWithComment) {
"\x00\x00\x00\x18tEXthave some\x00spaces in both\x8d\x69\x34\x2d";
EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected1,
- kExpected1 + arraysize(kExpected1)),
+ kExpected1 + base::size(kExpected1)),
encoded.end());
EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected2,
- kExpected2 + arraysize(kExpected2)),
+ kExpected2 + base::size(kExpected2)),
encoded.end());
EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected3,
- kExpected3 + arraysize(kExpected3)),
+ kExpected3 + base::size(kExpected3)),
encoded.end());
}
diff --git a/chromium/ui/gfx/color_analysis.cc b/chromium/ui/gfx/color_analysis.cc
index a23a9ad95c1..087069e12eb 100644
--- a/chromium/ui/gfx/color_analysis.cc
+++ b/chromium/ui/gfx/color_analysis.cc
@@ -541,8 +541,8 @@ SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
clusters.resize(kNumberOfClusters, KMeanCluster());
// Pick a starting point for each cluster
- auto cluster = clusters.begin();
- while (cluster != clusters.end()) {
+ auto new_cluster = clusters.begin();
+ while (new_cluster != clusters.end()) {
// Try up to 10 times to find a unique color. If no unique color can be
// found, destroy this cluster.
bool color_unique = false;
@@ -562,9 +562,9 @@ SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
// Loop through the previous clusters and check to see if we have seen
// this color before.
color_unique = true;
- for (auto cluster_check = clusters.begin(); cluster_check != cluster;
- ++cluster_check) {
- if (cluster_check->IsAtCentroid(r, g, b)) {
+ for (auto cluster = clusters.begin(); cluster != new_cluster;
+ ++cluster) {
+ if (cluster->IsAtCentroid(r, g, b)) {
color_unique = false;
break;
}
@@ -573,19 +573,19 @@ SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
// If we have a unique color set the center of the cluster to
// that color.
if (color_unique) {
- cluster->SetCentroid(r, g, b);
+ new_cluster->SetCentroid(r, g, b);
break;
}
}
// If we don't have a unique color erase this cluster.
if (!color_unique) {
- cluster = clusters.erase(cluster);
+ new_cluster = clusters.erase(new_cluster);
} else {
// Have to increment the iterator here, otherwise the increment in the
// for loop will skip a cluster due to the erase if the color wasn't
// unique.
- ++cluster;
+ ++new_cluster;
}
}
diff --git a/chromium/ui/gfx/color_palette.h b/chromium/ui/gfx/color_palette.h
index d17425b1e54..5cf5d707bb0 100644
--- a/chromium/ui/gfx/color_palette.h
+++ b/chromium/ui/gfx/color_palette.h
@@ -15,30 +15,60 @@ 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 kGoogleBlue050 = SkColorSetRGB(0xE8, 0xF0, 0xFE);
constexpr SkColor kGoogleBlue100 = SkColorSetRGB(0xD2, 0xE3, 0xFC);
+constexpr SkColor kGoogleBlue200 = SkColorSetRGB(0xAE, 0xCB, 0xFA);
constexpr SkColor kGoogleBlue300 = SkColorSetRGB(0x8A, 0xB4, 0xF8);
+constexpr SkColor kGoogleBlue400 = SkColorSetRGB(0x66, 0x9D, 0xF6);
constexpr SkColor kGoogleBlue500 = SkColorSetRGB(0x42, 0x85, 0xF4);
constexpr SkColor kGoogleBlue600 = SkColorSetRGB(0x1A, 0x73, 0xE8);
constexpr SkColor kGoogleBlue700 = SkColorSetRGB(0x19, 0x67, 0xD2);
+constexpr SkColor kGoogleBlue800 = SkColorSetRGB(0x18, 0x5A, 0xBC);
constexpr SkColor kGoogleBlue900 = SkColorSetRGB(0x17, 0x4E, 0xA6);
+
constexpr SkColor kGoogleBlueDark400 = SkColorSetRGB(0x6B, 0xA5, 0xED);
constexpr SkColor kGoogleBlueDark600 = SkColorSetRGB(0x25, 0x81, 0xDF);
-constexpr SkColor kGoogleRed300 = SkColorSetRGB(0xF2, 0x8B, 0xB2);
+
+constexpr SkColor kGoogleRed050 = SkColorSetRGB(0xFC, 0x8E, 0xE6);
+constexpr SkColor kGoogleRed100 = SkColorSetRGB(0xFA, 0xD2, 0xCF);
+constexpr SkColor kGoogleRed200 = SkColorSetRGB(0xF6, 0xAE, 0xA9);
+constexpr SkColor kGoogleRed300 = SkColorSetRGB(0xF2, 0x8B, 0x82);
+constexpr SkColor kGoogleRed400 = SkColorSetRGB(0xEE, 0x67, 0x5C);
constexpr SkColor kGoogleRed500 = SkColorSetRGB(0xEA, 0x43, 0x35);
constexpr SkColor kGoogleRed600 = SkColorSetRGB(0xD9, 0x30, 0x25);
constexpr SkColor kGoogleRed700 = SkColorSetRGB(0xC5, 0x22, 0x1F);
constexpr SkColor kGoogleRed800 = SkColorSetRGB(0xB3, 0x14, 0x12);
+constexpr SkColor kGoogleRed900 = SkColorSetRGB(0xA5, 0x0E, 0x0E);
+
constexpr SkColor kGoogleRedDark500 = SkColorSetRGB(0xE6, 0x6A, 0x5E);
constexpr SkColor kGoogleRedDark600 = SkColorSetRGB(0xD3, 0x3B, 0x30);
constexpr SkColor kGoogleRedDark800 = SkColorSetRGB(0xB4, 0x1B, 0x1A);
+
+constexpr SkColor kGoogleGreen050 = SkColorSetRGB(0xE6, 0xF4, 0xEA);
+constexpr SkColor kGoogleGreen100 = SkColorSetRGB(0xCE, 0xEA, 0xD6);
+constexpr SkColor kGoogleGreen200 = SkColorSetRGB(0xA8, 0xDA, 0xB5);
constexpr SkColor kGoogleGreen300 = SkColorSetRGB(0x81, 0xC9, 0x95);
+constexpr SkColor kGoogleGreen400 = SkColorSetRGB(0x5B, 0xB9, 0x74);
+constexpr SkColor kGoogleGreen500 = SkColorSetRGB(0x34, 0xA8, 0x53);
constexpr SkColor kGoogleGreen600 = SkColorSetRGB(0x1E, 0x8E, 0x3E);
constexpr SkColor kGoogleGreen700 = SkColorSetRGB(0x18, 0x80, 0x38);
+constexpr SkColor kGoogleGreen800 = SkColorSetRGB(0x13, 0x73, 0x33);
+constexpr SkColor kGoogleGreen900 = SkColorSetRGB(0x0D, 0x65, 0x2D);
+
constexpr SkColor kGoogleGreenDark500 = SkColorSetRGB(0x41, 0xAF, 0x6A);
constexpr SkColor kGoogleGreenDark600 = SkColorSetRGB(0x28, 0x99, 0x4F);
+
+constexpr SkColor kGoogleYellow050 = SkColorSetRGB(0xFE, 0xF7, 0xE0);
+constexpr SkColor kGoogleYellow100 = SkColorSetRGB(0xFE, 0xEF, 0xC3);
+constexpr SkColor kGoogleYellow200 = SkColorSetRGB(0xFB, 0xBC, 0x04);
constexpr SkColor kGoogleYellow300 = SkColorSetRGB(0xFD, 0xD6, 0x63);
+constexpr SkColor kGoogleYellow400 = SkColorSetRGB(0xFC, 0xC9, 0x34);
+constexpr SkColor kGoogleYellow500 = SkColorSetRGB(0xFB, 0xBC, 0x04);
+constexpr SkColor kGoogleYellow600 = SkColorSetRGB(0xF9, 0xAB, 0x00);
constexpr SkColor kGoogleYellow700 = SkColorSetRGB(0xF2, 0x99, 0x00);
+constexpr SkColor kGoogleYellow800 = SkColorSetRGB(0xEA, 0x86, 0x00);
constexpr SkColor kGoogleYellow900 = SkColorSetRGB(0xE3, 0x74, 0x00);
+
constexpr SkColor kGoogleGrey050 = SkColorSetRGB(0xF8, 0xF9, 0xFA);
constexpr SkColor kGoogleGrey100 = SkColorSetRGB(0xF1, 0xF3, 0xF4);
constexpr SkColor kGoogleGrey200 = SkColorSetRGB(0xE8, 0xEA, 0xED);
diff --git a/chromium/ui/gfx/color_space.cc b/chromium/ui/gfx/color_space.cc
index 7984428cbb9..93bc1306701 100644
--- a/chromium/ui/gfx/color_space.cc
+++ b/chromium/ui/gfx/color_space.cc
@@ -10,7 +10,6 @@
#include <sstream>
#include "base/atomic_sequence_num.h"
-#include "base/containers/mru_cache.h"
#include "base/lazy_instance.h"
#include "base/synchronization/lock.h"
#include "third_party/skia/include/core/SkColorSpace.h"
@@ -25,24 +24,22 @@ namespace {
base::AtomicSequenceNumber g_color_space_id;
-// See comments in ToSkColorSpace about this cache. This cache may only be
-// accessed while holding g_sk_color_space_cache_lock.
-static const size_t kMaxCachedSkColorSpaces = 16;
-using SkColorSpaceCacheBase =
- base::MRUCache<gfx::ColorSpace, sk_sp<SkColorSpace>>;
-class SkColorSpaceCache : public SkColorSpaceCacheBase {
- public:
- SkColorSpaceCache() : SkColorSpaceCacheBase(kMaxCachedSkColorSpaces) {}
-};
-base::LazyInstance<SkColorSpaceCache>::Leaky g_sk_color_space_cache =
- LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<base::Lock>::Leaky g_sk_color_space_cache_lock =
- LAZY_INSTANCE_INITIALIZER;
-
static bool IsAlmostZero(float value) {
return std::abs(value) < std::numeric_limits<float>::epsilon();
}
+static bool FloatsEqualWithinTolerance(const float* a,
+ const float* b,
+ int n,
+ float tol) {
+ for (int i = 0; i < n; ++i) {
+ if (std::abs(a[i] - b[i]) > tol) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace
// static
@@ -68,56 +65,15 @@ ColorSpace::ColorSpace(const SkColorSpace& sk_color_space)
TransferID::INVALID,
MatrixID::RGB,
RangeID::FULL) {
- switch (sk_color_space.gammaNamed()) {
- case kLinear_SkGammaNamed:
- transfer_ = TransferID::LINEAR;
- break;
- case kSRGB_SkGammaNamed:
- transfer_ = TransferID::IEC61966_2_1;
- break;
- default: {
- SkColorSpaceTransferFn transfer_fn;
- if (sk_color_space.isNumericalTransferFn(&transfer_fn)) {
- transfer_ = TransferID::CUSTOM;
- SetCustomTransferFunction(transfer_fn);
- } else {
- // Construct an invalid result: Unable to determine transfer function.
- return;
- }
- break;
- }
- }
-
- // As of this writing, Skia doesn't provide a property accessor for its named
- // gamuts. Therefore, the following attempts to detect by "guess and check"
- // for the commonly-used primaries.
- primaries_ = PrimaryID::BT709;
- if (SkColorSpace::Equals(&sk_color_space, ToSkColorSpace().get())) {
- return;
- }
- primaries_ = PrimaryID::ADOBE_RGB;
- if (SkColorSpace::Equals(&sk_color_space, ToSkColorSpace().get())) {
- return;
- }
- primaries_ = PrimaryID::SMPTEST432_1;
- if (SkColorSpace::Equals(&sk_color_space, ToSkColorSpace().get())) {
+ SkColorSpaceTransferFn fn;
+ skcms_Matrix3x3 to_XYZD50;
+ if (!sk_color_space.isNumericalTransferFn(&fn) ||
+ !sk_color_space.toXYZD50(&to_XYZD50)) {
+ // Construct an invalid result: Unable to extract necessary parameters
return;
}
- primaries_ = PrimaryID::BT2020;
- if (SkColorSpace::Equals(&sk_color_space, ToSkColorSpace().get())) {
- return;
- }
-
- // Use custom primaries, if they are representable as a "to XYZD50" matrix.
- SkMatrix44 to_XYZD50{SkMatrix44::kUninitialized_Constructor};
- if (sk_color_space.toXYZD50(&to_XYZD50)) {
- primaries_ = PrimaryID::CUSTOM;
- SetCustomPrimaries(to_XYZD50);
- return;
- }
-
- // If this point is reached, there is no way to represent the primaries.
- primaries_ = PrimaryID::INVALID;
+ SetCustomTransferFunction(fn);
+ SetCustomPrimaries(to_XYZD50);
}
bool ColorSpace::IsValid() const {
@@ -126,7 +82,7 @@ bool ColorSpace::IsValid() const {
}
// static
-ColorSpace ColorSpace::CreateCustom(const SkMatrix44& to_XYZD50,
+ColorSpace ColorSpace::CreateCustom(const skcms_Matrix3x3& to_XYZD50,
const SkColorSpaceTransferFn& fn) {
ColorSpace result(ColorSpace::PrimaryID::CUSTOM,
ColorSpace::TransferID::CUSTOM, ColorSpace::MatrixID::RGB,
@@ -136,16 +92,57 @@ ColorSpace ColorSpace::CreateCustom(const SkMatrix44& to_XYZD50,
return result;
}
-void ColorSpace::SetCustomPrimaries(const SkMatrix44& to_XYZD50) {
- for (int row = 0; row < 3; ++row) {
- for (int col = 0; col < 3; ++col) {
- custom_primary_matrix_[3 * row + col] = to_XYZD50.get(row, col);
+void ColorSpace::SetCustomPrimaries(const skcms_Matrix3x3& to_XYZD50) {
+ const PrimaryID kIDsToCheck[] = {
+ PrimaryID::BT709,
+ PrimaryID::BT470M,
+ PrimaryID::BT470BG,
+ PrimaryID::SMPTE170M,
+ PrimaryID::SMPTE240M,
+ PrimaryID::FILM,
+ PrimaryID::BT2020,
+ PrimaryID::SMPTEST428_1,
+ PrimaryID::SMPTEST431_2,
+ PrimaryID::SMPTEST432_1,
+ PrimaryID::XYZ_D50,
+ PrimaryID::ADOBE_RGB,
+ PrimaryID::APPLE_GENERIC_RGB,
+ PrimaryID::WIDE_GAMUT_COLOR_SPIN,
+ };
+ for (PrimaryID id : kIDsToCheck) {
+ skcms_Matrix3x3 matrix;
+ GetPrimaryMatrix(id, &matrix);
+ if (FloatsEqualWithinTolerance(&to_XYZD50.vals[0][0], &matrix.vals[0][0], 9,
+ 0.001f)) {
+ primaries_ = id;
+ return;
}
}
+
+ memcpy(custom_primary_matrix_, &to_XYZD50, 9 * sizeof(float));
primaries_ = PrimaryID::CUSTOM;
}
void ColorSpace::SetCustomTransferFunction(const SkColorSpaceTransferFn& fn) {
+ // These are all TransferIDs that will return a transfer function from
+ // GetTransferFunction. When multiple ids map to the same function, this list
+ // prioritizes the most common name (eg IEC61966_2_1).
+ const TransferID kIDsToCheck[] = {
+ TransferID::IEC61966_2_1, TransferID::LINEAR,
+ TransferID::GAMMA18, TransferID::GAMMA22,
+ TransferID::GAMMA24, TransferID::GAMMA28,
+ TransferID::SMPTE240M, TransferID::BT709_APPLE,
+ TransferID::SMPTEST428_1,
+ };
+ for (TransferID id : kIDsToCheck) {
+ SkColorSpaceTransferFn id_fn;
+ GetTransferFunction(id, &id_fn);
+ if (FloatsEqualWithinTolerance(&fn.fG, &id_fn.fG, 7, 0.001f)) {
+ transfer_ = id;
+ return;
+ }
+ }
+
custom_transfer_params_[0] = fn.fA;
custom_transfer_params_[1] = fn.fB;
custom_transfer_params_[2] = fn.fC;
@@ -153,22 +150,10 @@ void ColorSpace::SetCustomTransferFunction(const SkColorSpaceTransferFn& fn) {
custom_transfer_params_[4] = fn.fE;
custom_transfer_params_[5] = fn.fF;
custom_transfer_params_[6] = fn.fG;
- // TODO(ccameron): Use enums for near matches to know color spaces.
transfer_ = TransferID::CUSTOM;
}
// static
-ColorSpace ColorSpace::CreateCustom(const SkMatrix44& to_XYZD50,
- ColorSpace::TransferID transfer_id) {
- DCHECK_NE(transfer_id, ColorSpace::TransferID::CUSTOM);
- DCHECK_NE(transfer_id, ColorSpace::TransferID::INVALID);
- ColorSpace result(ColorSpace::PrimaryID::CUSTOM, transfer_id,
- ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
- result.SetCustomPrimaries(to_XYZD50);
- return result;
-}
-
-// static
int ColorSpace::GetNextId() {
return g_color_space_id.GetNext();
}
@@ -311,22 +296,22 @@ std::string ColorSpace::ToString() const {
PRINT_ENUM_CASE(PrimaryID, APPLE_GENERIC_RGB)
PRINT_ENUM_CASE(PrimaryID, WIDE_GAMUT_COLOR_SPIN)
case PrimaryID::CUSTOM:
- // |custom_primary_matrix_| is in column-major order.
- const float sum_X = custom_primary_matrix_[0] +
+ // |custom_primary_matrix_| is in row-major order.
+ const float sum_R = custom_primary_matrix_[0] +
custom_primary_matrix_[3] + custom_primary_matrix_[6];
- const float sum_Y = custom_primary_matrix_[1] +
+ const float sum_G = custom_primary_matrix_[1] +
custom_primary_matrix_[4] + custom_primary_matrix_[7];
- const float sum_Z = custom_primary_matrix_[2] +
+ const float sum_B = custom_primary_matrix_[2] +
custom_primary_matrix_[5] + custom_primary_matrix_[8];
- if (IsAlmostZero(sum_X) || IsAlmostZero(sum_Y) || IsAlmostZero(sum_Z))
+ if (IsAlmostZero(sum_R) || IsAlmostZero(sum_G) || IsAlmostZero(sum_B))
break;
- ss << "{primaries_d50_referred: [[" << (custom_primary_matrix_[0] / sum_X)
- << ", " << (custom_primary_matrix_[3] / sum_X) << "], "
- << " [" << (custom_primary_matrix_[1] / sum_Y) << ", "
- << (custom_primary_matrix_[4] / sum_Y) << "], "
- << " [" << (custom_primary_matrix_[2] / sum_Z) << ", "
- << (custom_primary_matrix_[5] / sum_Z) << "]]";
+ ss << "{primaries_d50_referred: [[" << (custom_primary_matrix_[0] / sum_R)
+ << ", " << (custom_primary_matrix_[3] / sum_R) << "], "
+ << " [" << (custom_primary_matrix_[1] / sum_G) << ", "
+ << (custom_primary_matrix_[4] / sum_G) << "], "
+ << " [" << (custom_primary_matrix_[2] / sum_B) << ", "
+ << (custom_primary_matrix_[5] / sum_B) << "]]";
break;
}
ss << ", transfer:";
@@ -411,11 +396,11 @@ ColorSpace ColorSpace::GetAsRGB() const {
ColorSpace ColorSpace::GetScaledColorSpace(float factor) const {
ColorSpace result(*this);
- SkMatrix44 to_XYZD50;
+ skcms_Matrix3x3 to_XYZD50;
GetPrimaryMatrix(&to_XYZD50);
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
- to_XYZD50.set(row, col, to_XYZD50.get(row, col) * factor);
+ to_XYZD50.vals[row][col] *= factor;
}
}
result.SetCustomPrimaries(to_XYZD50);
@@ -473,8 +458,6 @@ sk_sp<SkColorSpace> ColorSpace::ToSkColorSpace() const {
}
// Use the named SRGB and linear-SRGB instead of the generic constructors.
- // These do not need to be cached because skia will always return the same
- // pointer.
if (primaries_ == PrimaryID::BT709) {
if (transfer_ == TransferID::IEC61966_2_1)
return SkColorSpace::MakeSRGB();
@@ -482,84 +465,55 @@ sk_sp<SkColorSpace> ColorSpace::ToSkColorSpace() const {
return SkColorSpace::MakeSRGBLinear();
}
- // Prefer to used the named gamma and gamut, if possible.
- bool has_named_gamma = true;
- SkColorSpace::RenderTargetGamma named_gamma =
- SkColorSpace::kSRGB_RenderTargetGamma;
- SkColorSpaceTransferFn custom_gamma;
+ skcms_TransferFunction transfer_fn = SkNamedTransferFn::kSRGB;
switch (transfer_) {
case TransferID::IEC61966_2_1:
break;
case TransferID::LINEAR:
case TransferID::LINEAR_HDR:
- named_gamma = SkColorSpace::kLinear_RenderTargetGamma;
+ transfer_fn = SkNamedTransferFn::kLinear;
break;
default:
- has_named_gamma = false;
- if (!GetTransferFunction(&custom_gamma)) {
+ if (!GetTransferFunction((SkColorSpaceTransferFn*)&transfer_fn)) {
DLOG(ERROR) << "Failed to transfer function for SkColorSpace";
return nullptr;
}
break;
}
- bool has_named_gamut = true;
- SkColorSpace::Gamut named_gamut = SkColorSpace::kSRGB_Gamut;
- SkMatrix44 custom_gamut;
+ skcms_Matrix3x3 gamut = SkNamedGamut::kSRGB;
switch (primaries_) {
case PrimaryID::BT709:
break;
case PrimaryID::ADOBE_RGB:
- named_gamut = SkColorSpace::kAdobeRGB_Gamut;
+ gamut = SkNamedGamut::kAdobeRGB;
break;
case PrimaryID::SMPTEST432_1:
- named_gamut = SkColorSpace::kDCIP3_D65_Gamut;
+ gamut = SkNamedGamut::kDCIP3;
break;
case PrimaryID::BT2020:
- named_gamut = SkColorSpace::kRec2020_Gamut;
+ gamut = SkNamedGamut::kRec2020;
break;
default:
- has_named_gamut = false;
- GetPrimaryMatrix(&custom_gamut);
+ GetPrimaryMatrix(&gamut);
break;
}
- // Maintain a gfx::ColorSpace to SkColorSpace map, so that pointer-based
- // comparisons of SkColorSpaces will be more likely to be accurate.
- // https://crbug.com/793116
- base::AutoLock lock(g_sk_color_space_cache_lock.Get());
-
- auto found = g_sk_color_space_cache.Get().Get(*this);
- if (found != g_sk_color_space_cache.Get().end())
- return found->second;
-
- sk_sp<SkColorSpace> sk_color_space;
- if (has_named_gamma) {
- if (has_named_gamut)
- sk_color_space = SkColorSpace::MakeRGB(named_gamma, named_gamut);
- else
- sk_color_space = SkColorSpace::MakeRGB(named_gamma, custom_gamut);
- } else {
- if (has_named_gamut)
- sk_color_space = SkColorSpace::MakeRGB(custom_gamma, named_gamut);
- else
- sk_color_space = SkColorSpace::MakeRGB(custom_gamma, custom_gamut);
- }
+ sk_sp<SkColorSpace> sk_color_space =
+ SkColorSpace::MakeRGB(transfer_fn, gamut);
if (!sk_color_space)
DLOG(ERROR) << "SkColorSpace::MakeRGB failed.";
- g_sk_color_space_cache.Get().Put(*this, sk_color_space);
return sk_color_space;
}
-void ColorSpace::GetPrimaryMatrix(SkMatrix44* to_XYZD50) const {
+// static
+void ColorSpace::GetPrimaryMatrix(PrimaryID primary_id,
+ skcms_Matrix3x3* to_XYZD50) {
SkColorSpacePrimaries primaries = {0};
- switch (primaries_) {
+ switch (primary_id) {
case ColorSpace::PrimaryID::CUSTOM:
- to_XYZD50->set3x3RowMajorf(custom_primary_matrix_);
- return;
-
case ColorSpace::PrimaryID::INVALID:
- to_XYZD50->setIdentity();
+ *to_XYZD50 = SkNamedGamut::kXYZ; // Identity
return;
case ColorSpace::PrimaryID::BT709:
@@ -713,26 +667,33 @@ void ColorSpace::GetPrimaryMatrix(SkMatrix44* to_XYZD50) const {
primaries.toXYZD50(to_XYZD50);
}
-bool ColorSpace::GetTransferFunction(SkColorSpaceTransferFn* fn) const {
+void ColorSpace::GetPrimaryMatrix(skcms_Matrix3x3* to_XYZD50) const {
+ if (primaries_ == PrimaryID::CUSTOM) {
+ memcpy(to_XYZD50, custom_primary_matrix_, 9 * sizeof(float));
+ } else {
+ GetPrimaryMatrix(primaries_, to_XYZD50);
+ }
+}
+
+void ColorSpace::GetPrimaryMatrix(SkMatrix44* to_XYZD50) const {
+ skcms_Matrix3x3 toXYZ_3x3;
+ GetPrimaryMatrix(&toXYZ_3x3);
+ to_XYZD50->set3x3RowMajorf(&toXYZ_3x3.vals[0][0]);
+}
+
+// static
+bool ColorSpace::GetTransferFunction(TransferID transfer,
+ SkColorSpaceTransferFn* fn) {
// Default to F(x) = pow(x, 1)
fn->fA = 1;
fn->fB = 0;
- fn->fC = 1;
+ fn->fC = 0;
fn->fD = 0;
fn->fE = 0;
fn->fF = 0;
fn->fG = 1;
- switch (transfer_) {
- case ColorSpace::TransferID::CUSTOM:
- fn->fA = custom_transfer_params_[0];
- fn->fB = custom_transfer_params_[1];
- fn->fC = custom_transfer_params_[2];
- fn->fD = custom_transfer_params_[3];
- fn->fE = custom_transfer_params_[4];
- fn->fF = custom_transfer_params_[5];
- fn->fG = custom_transfer_params_[6];
- return true;
+ switch (transfer) {
case ColorSpace::TransferID::LINEAR:
case ColorSpace::TransferID::LINEAR_HDR:
return true;
@@ -794,6 +755,7 @@ bool ColorSpace::GetTransferFunction(SkColorSpaceTransferFn* fn) const {
case ColorSpace::TransferID::LOG_SQRT:
case ColorSpace::TransferID::SMPTEST2084:
case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
+ case ColorSpace::TransferID::CUSTOM:
case ColorSpace::TransferID::INVALID:
break;
}
@@ -801,6 +763,21 @@ bool ColorSpace::GetTransferFunction(SkColorSpaceTransferFn* fn) const {
return false;
}
+bool ColorSpace::GetTransferFunction(SkColorSpaceTransferFn* fn) const {
+ if (transfer_ == TransferID::CUSTOM) {
+ fn->fA = custom_transfer_params_[0];
+ fn->fB = custom_transfer_params_[1];
+ fn->fC = custom_transfer_params_[2];
+ fn->fD = custom_transfer_params_[3];
+ fn->fE = custom_transfer_params_[4];
+ fn->fF = custom_transfer_params_[5];
+ fn->fG = custom_transfer_params_[6];
+ return true;
+ } else {
+ return GetTransferFunction(transfer_, fn);
+ }
+}
+
bool ColorSpace::GetInverseTransferFunction(SkColorSpaceTransferFn* fn) const {
if (!GetTransferFunction(fn))
return false;
diff --git a/chromium/ui/gfx/color_space.h b/chromium/ui/gfx/color_space.h
index f238b5383de..e3028d7b714 100644
--- a/chromium/ui/gfx/color_space.h
+++ b/chromium/ui/gfx/color_space.h
@@ -149,9 +149,7 @@ class COLOR_SPACE_EXPORT ColorSpace {
return ColorSpace(PrimaryID::SMPTEST432_1, TransferID::IEC61966_2_1,
MatrixID::RGB, RangeID::FULL);
}
- static ColorSpace CreateCustom(const SkMatrix44& to_XYZD50,
- TransferID transfer_id);
- static ColorSpace CreateCustom(const SkMatrix44& to_XYZD50,
+ static ColorSpace CreateCustom(const skcms_Matrix3x3& to_XYZD50,
const SkColorSpaceTransferFn& fn);
static constexpr ColorSpace CreateXYZD50() {
return ColorSpace(PrimaryID::XYZ_D50, TransferID::LINEAR, MatrixID::RGB,
@@ -240,6 +238,7 @@ class COLOR_SPACE_EXPORT ColorSpace {
// Returns true if a close match is found.
bool ToSkYUVColorSpace(SkYUVColorSpace* out) const;
+ void GetPrimaryMatrix(skcms_Matrix3x3* to_XYZD50) const;
void GetPrimaryMatrix(SkMatrix44* to_XYZD50) const;
bool GetTransferFunction(SkColorSpaceTransferFn* fn) const;
bool GetInverseTransferFunction(SkColorSpaceTransferFn* fn) const;
@@ -249,8 +248,11 @@ class COLOR_SPACE_EXPORT ColorSpace {
void GetRangeAdjustMatrix(SkMatrix44* matrix) const;
private:
+ static void GetPrimaryMatrix(PrimaryID, skcms_Matrix3x3* to_XYZD50);
+ static bool GetTransferFunction(TransferID, SkColorSpaceTransferFn* fn);
+
void SetCustomTransferFunction(const SkColorSpaceTransferFn& fn);
- void SetCustomPrimaries(const SkMatrix44& to_XYZD50);
+ void SetCustomPrimaries(const skcms_Matrix3x3& to_XYZD50);
// Returns true if the transfer function is defined by an
// SkColorSpaceTransferFn which is extended to all real values.
diff --git a/chromium/ui/gfx/color_space_unittest.cc b/chromium/ui/gfx/color_space_unittest.cc
index 86896d0603b..b2cf51eac4f 100644
--- a/chromium/ui/gfx/color_space_unittest.cc
+++ b/chromium/ui/gfx/color_space_unittest.cc
@@ -101,10 +101,16 @@ TEST(ColorSpace, RasterAndBlend) {
TEST(ColorSpace, ConversionToAndFromSkColorSpace) {
const size_t kNumTests = 5;
- SkMatrix44 primary_matrix;
- primary_matrix.set3x3(0.205276f, 0.149185f, 0.609741f, 0.625671f, 0.063217f,
- 0.311111f, 0.060867f, 0.744553f, 0.019470f);
- SkColorSpaceTransferFn transfer_fn = {2.1f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+ skcms_Matrix3x3 primary_matrix = {{
+ {0.205276f, 0.625671f, 0.060867f},
+ {0.149185f, 0.063217f, 0.744553f},
+ {0.609741f, 0.311111f, 0.019470f},
+ }};
+ skcms_TransferFunction transfer_fn = {2.1f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+
+ SkColorSpaceTransferFn sk_transfer_fn;
+ memcpy(&sk_transfer_fn, &transfer_fn, sizeof(sk_transfer_fn));
+
ColorSpace color_spaces[kNumTests] = {
ColorSpace(ColorSpace::PrimaryID::BT709,
ColorSpace::TransferID::IEC61966_2_1),
@@ -114,39 +120,22 @@ TEST(ColorSpace, ConversionToAndFromSkColorSpace) {
ColorSpace::TransferID::LINEAR),
ColorSpace(ColorSpace::PrimaryID::BT2020,
ColorSpace::TransferID::IEC61966_2_1),
- ColorSpace::CreateCustom(primary_matrix, transfer_fn),
+ ColorSpace::CreateCustom(primary_matrix, sk_transfer_fn),
};
sk_sp<SkColorSpace> sk_color_spaces[kNumTests] = {
SkColorSpace::MakeSRGB(),
- SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
- SkColorSpace::kAdobeRGB_Gamut),
- SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kDCIP3_D65_Gamut),
- SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
- SkColorSpace::kRec2020_Gamut),
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB),
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, SkNamedGamut::kDCIP3),
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kRec2020),
SkColorSpace::MakeRGB(transfer_fn, primary_matrix),
};
// Test that converting from ColorSpace to SkColorSpace is producing an
- // equivalent representation, and that the SkColorSpace ref-pointers are being
- // globally cached.
- sk_sp<SkColorSpace> got_sk_color_spaces[kNumTests];
- for (size_t i = 0; i < kNumTests; ++i)
- got_sk_color_spaces[i] = color_spaces[i].ToSkColorSpace();
+ // equivalent representation.
for (size_t i = 0; i < kNumTests; ++i) {
- EXPECT_TRUE(SkColorSpace::Equals(got_sk_color_spaces[i].get(),
+ EXPECT_TRUE(SkColorSpace::Equals(color_spaces[i].ToSkColorSpace().get(),
sk_color_spaces[i].get()))
<< " on iteration i = " << i;
- // ToSkColorSpace should return the same thing every time.
- EXPECT_EQ(got_sk_color_spaces[i].get(),
- color_spaces[i].ToSkColorSpace().get())
- << " on iteration i = " << i;
- // But there is no cache within Skia, except for sRGB.
- // This test may start failing if this behavior changes.
- if (i != 0) {
- EXPECT_NE(got_sk_color_spaces[i].get(), sk_color_spaces[i].get())
- << " on iteration i = " << i;
- }
}
// Invariant test: Test that converting a SkColorSpace to a ColorSpace is
diff --git a/chromium/ui/gfx/color_space_win.cc b/chromium/ui/gfx/color_space_win.cc
index 9e5a0fc8e34..7f645185325 100644
--- a/chromium/ui/gfx/color_space_win.cc
+++ b/chromium/ui/gfx/color_space_win.cc
@@ -208,10 +208,11 @@ DXGI_COLOR_SPACE_TYPE ColorSpaceWin::GetDXGIColorSpace(
D3D11_VIDEO_PROCESSOR_COLOR_SPACE ColorSpaceWin::GetD3D11ColorSpace(
const ColorSpace& color_space) {
D3D11_VIDEO_PROCESSOR_COLOR_SPACE ret = {0};
- if (color_space.range_ != gfx::ColorSpace::RangeID::FULL) {
- ret.RGB_Range = 1;
+ if (color_space.range_ == gfx::ColorSpace::RangeID::FULL) {
+ ret.RGB_Range = 0; // FULL
ret.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255;
} else {
+ ret.RGB_Range = 1; // LIMITED
ret.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235;
}
diff --git a/chromium/ui/gfx/color_transform_unittest.cc b/chromium/ui/gfx/color_transform_unittest.cc
index 96cab26abdf..8a1c396e99b 100644
--- a/chromium/ui/gfx/color_transform_unittest.cc
+++ b/chromium/ui/gfx/color_transform_unittest.cc
@@ -428,7 +428,7 @@ TEST(SimpleColorSpace, DefaultToSRGB) {
// This tests to make sure that we don't emit "pow" parts of a
// transfer function unless necessary.
TEST(SimpleColorSpace, ShaderSourceTrFnOptimizations) {
- SkMatrix44 primaries;
+ skcms_Matrix3x3 primaries;
gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&primaries);
SkColorSpaceTransferFn fn_no_pow = {
@@ -474,7 +474,7 @@ TEST(SimpleColorSpace, SampleShaderSource) {
"}\n"
"float TransferFn3(float v) {\n"
" if (v < 0.00000000e+00)\n"
- " return v;\n"
+ " return 0.00000000e+00 * v;\n"
" return pow(v, 3.57142866e-01);\n"
"}\n"
"vec3 DoColorConversion(vec3 color) {\n"
diff --git a/chromium/ui/gfx/color_utils.cc b/chromium/ui/gfx/color_utils.cc
index 9edd09b4180..c868cd54bac 100644
--- a/chromium/ui/gfx/color_utils.cc
+++ b/chromium/ui/gfx/color_utils.cc
@@ -28,10 +28,14 @@ namespace color_utils {
namespace {
// The darkest reference color in color_utils.
-SkColor g_color_utils_darkest = SK_ColorBLACK;
+SkColor g_darkest_color = gfx::kGoogleGrey900;
-// The luma midpoint for determining if a color is light or dark.
-int g_color_utils_luma_midpoint = 128;
+// The luminance midpoint for determining if a color is light or dark. This is
+// the value where white and g_darkest_color contrast equally. This default
+// value is the midpoint given kGoogleGrey900 as the darkest color.
+float g_luminance_midpoint = 0.211692036f;
+
+constexpr float kWhiteLuminance = 1.0f;
int calcHue(float temp1, float temp2, float hue) {
if (hue < 0.0f)
@@ -60,13 +64,6 @@ float Linearize(float eight_bit_component) {
: pow((component + 0.055f) / 1.055f, 2.4f);
}
-SkColor LightnessInvertColor(SkColor color) {
- HSL hsl;
- SkColorToHSL(color, &hsl);
- hsl.l = 1.0f - hsl.l;
- return HSLToSkColor(hsl, SkColorGetA(color));
-}
-
} // namespace
float GetContrastRatio(SkColor color_a, SkColor color_b) {
@@ -99,8 +96,8 @@ void SkColorToHSL(SkColor c, HSL* hsl) {
float r = SkColorGetR(c) / 255.0f;
float g = SkColorGetG(c) / 255.0f;
float b = SkColorGetB(c) / 255.0f;
- float vmax = std::max(std::max(r, g), b);
- float vmin = std::min(std::min(r, g), b);
+ float vmax = std::max({r, g, b});
+ float vmin = std::min({r, g, b});
float delta = vmax - vmin;
hsl->l = (vmax + vmin) / 2;
if (SkColorGetR(c) == SkColorGetG(c) && SkColorGetR(c) == SkColorGetB(c)) {
@@ -263,70 +260,57 @@ double CalculateBoringScore(const SkBitmap& bitmap) {
}
SkColor AlphaBlend(SkColor foreground, SkColor background, SkAlpha alpha) {
- if (alpha == 0)
+ return AlphaBlend(foreground, background, alpha / 255.0f);
+}
+
+SkColor AlphaBlend(SkColor foreground, SkColor background, float alpha) {
+ DCHECK_GE(alpha, 0.0f);
+ DCHECK_LE(alpha, 1.0f);
+
+ if (alpha == 0.0f)
return background;
- if (alpha == 255)
+ if (alpha == 1.0f)
return foreground;
int f_alpha = SkColorGetA(foreground);
int b_alpha = SkColorGetA(background);
- float normalizer = (f_alpha * alpha + b_alpha * (255 - alpha)) / 255.0f;
+ float normalizer = f_alpha * alpha + b_alpha * (1.0f - alpha);
if (normalizer == 0.0f)
return SK_ColorTRANSPARENT;
float f_weight = f_alpha * alpha / normalizer;
- float b_weight = b_alpha * (255 - alpha) / normalizer;
-
- float r = (SkColorGetR(foreground) * f_weight +
- SkColorGetR(background) * b_weight) /
- 255.0f;
- float g = (SkColorGetG(foreground) * f_weight +
- SkColorGetG(background) * b_weight) /
- 255.0f;
- float b = (SkColorGetB(foreground) * f_weight +
- SkColorGetB(background) * b_weight) /
- 255.0f;
-
- return SkColorSetARGB(static_cast<int>(std::round(normalizer)),
- static_cast<int>(std::round(r)),
- static_cast<int>(std::round(g)),
- static_cast<int>(std::round(b)));
+ float b_weight = b_alpha * (1.0f - alpha) / normalizer;
+
+ float r =
+ SkColorGetR(foreground) * f_weight + SkColorGetR(background) * b_weight;
+ float g =
+ SkColorGetG(foreground) * f_weight + SkColorGetG(background) * b_weight;
+ float b =
+ SkColorGetB(foreground) * f_weight + SkColorGetB(background) * b_weight;
+
+ return SkColorSetARGB(gfx::ToRoundedInt(normalizer), gfx::ToRoundedInt(r),
+ gfx::ToRoundedInt(g), gfx::ToRoundedInt(b));
}
SkColor GetResultingPaintColor(SkColor foreground, SkColor background) {
return AlphaBlend(SkColorSetA(foreground, SK_AlphaOPAQUE), background,
- SkColorGetA(foreground));
+ SkAlpha{SkColorGetA(foreground)});
}
bool IsDark(SkColor color) {
- return GetLuma(color) < g_color_utils_luma_midpoint;
-}
-
-SkColor BlendTowardOppositeLuma(SkColor color, SkAlpha alpha) {
- return AlphaBlend(IsDark(color) ? SK_ColorWHITE : g_color_utils_darkest,
- color, alpha);
+ return GetRelativeLuminance(color) < g_luminance_midpoint;
}
-SkColor GetThemedAssetColor(SkColor theme_color) {
- // Minimum theme light color contrast.
- constexpr float kContrastLightItemThreshold = 3;
-
- // The amount to darken a light theme color by for use as foreground color.
- constexpr float kThemedForegroundBlackFraction = 0.64;
-
- // This mimics |shouldUseLightForegroundOnBackground| from ColorUtils.java.
- bool use_light_color = GetContrastRatio(SK_ColorWHITE, theme_color) >=
- kContrastLightItemThreshold;
- if (use_light_color)
- return SK_ColorWHITE;
- return AlphaBlend(SK_ColorBLACK, theme_color,
- 255 * kThemedForegroundBlackFraction);
+SkColor GetColorWithMaxContrast(SkColor color) {
+ return IsDark(color) ? SK_ColorWHITE : g_darkest_color;
}
-SkColor GetReadableColor(SkColor foreground, SkColor background) {
- return PickContrastingColor(foreground, LightnessInvertColor(foreground),
- background);
+SkColor BlendTowardMaxContrast(SkColor color, SkAlpha alpha) {
+ SkAlpha original_alpha = SkColorGetA(color);
+ SkColor blended_color = AlphaBlend(GetColorWithMaxContrast(color),
+ SkColorSetA(color, SK_AlphaOPAQUE), alpha);
+ return SkColorSetA(blended_color, original_alpha);
}
SkColor PickContrastingColor(SkColor foreground1,
@@ -342,12 +326,11 @@ SkColor PickContrastingColor(SkColor foreground1,
SkColor GetColorWithMinimumContrast(SkColor default_foreground,
SkColor background) {
- const SkColor blend_direction =
- IsDark(background) ? SK_ColorWHITE : g_color_utils_darkest;
+ const SkColor contrasting_color = GetColorWithMaxContrast(background);
const SkAlpha alpha = GetBlendValueWithMinimumContrast(
- default_foreground, blend_direction, background,
+ default_foreground, contrasting_color, background,
kMinimumReadableContrastRatio);
- return AlphaBlend(blend_direction, default_foreground, alpha);
+ return AlphaBlend(contrasting_color, default_foreground, alpha);
}
SkAlpha GetBlendValueWithMinimumContrast(SkColor source,
@@ -382,9 +365,9 @@ SkAlpha FindBlendValueForContrastRatio(SkColor source,
// conversion to SkAlpha for the end (reduces casts).
int low = SK_AlphaTRANSPARENT;
int high = SK_AlphaOPAQUE + 1;
- int best = SK_AlphaOPAQUE;
+ SkAlpha best = SK_AlphaOPAQUE;
while (low + alpha_error_tolerance < high) {
- const int alpha = (low + high) / 2;
+ const SkAlpha alpha = (low + high) / 2;
const SkColor blended = AlphaBlend(target, source, alpha);
const float luminance = GetRelativeLuminance(blended);
const float contrast = GetContrastRatio(luminance, base_luminance);
@@ -422,7 +405,7 @@ bool IsInvertedColorScheme() {
SkColor DeriveDefaultIconColor(SkColor text_color) {
// Lighten dark colors and brighten light colors. The alpha value here (0x4c)
// is chosen to generate a value close to GoogleGrey700 from GoogleGrey900.
- return BlendTowardOppositeLuma(text_color, 0x4c);
+ return BlendTowardMaxContrast(text_color, 0x4c);
}
std::string SkColorToRgbaString(SkColor color) {
@@ -438,13 +421,24 @@ std::string SkColorToRgbString(SkColor color) {
SkColorGetB(color));
}
-void SetDarkestColor(SkColor color) {
- g_color_utils_darkest = color;
- g_color_utils_luma_midpoint = (GetLuma(color) + 255) / 2;
+SkColor SetDarkestColorForTesting(SkColor color) {
+ const SkColor previous_darkest_color = g_darkest_color;
+ g_darkest_color = color;
+
+ const float dark_luminance = GetRelativeLuminance(color);
+ // We want to compute |g_luminance_midpoint| such that
+ // GetContrastRatio(dark_luminance, g_luminance_midpoint) ==
+ // GetContrastRatio(kWhiteLuminance, g_luminance_midpoint). The formula below
+ // can be verified by plugging it into how GetContrastRatio() operates.
+ g_luminance_midpoint =
+ std::sqrtf((dark_luminance + 0.05f) * (kWhiteLuminance + 0.05f)) - 0.05f;
+
+ return previous_darkest_color;
}
-SkColor GetDarkestColor() {
- return g_color_utils_darkest;
+std::tuple<float, float, float> GetLuminancesForTesting() {
+ return std::make_tuple(GetRelativeLuminance(g_darkest_color),
+ g_luminance_midpoint, kWhiteLuminance);
}
} // namespace color_utils
diff --git a/chromium/ui/gfx/color_utils.h b/chromium/ui/gfx/color_utils.h
index 80b3504cd93..c443749445c 100644
--- a/chromium/ui/gfx/color_utils.h
+++ b/chromium/ui/gfx/color_utils.h
@@ -6,6 +6,7 @@
#define UI_GFX_COLOR_UTILS_H_
#include <string>
+#include <tuple>
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/gfx_export.h"
@@ -97,34 +98,30 @@ GFX_EXPORT double CalculateBoringScore(const SkBitmap& bitmap);
// |alpha| == 0) to |foreground| (for |alpha| == 255). The alpha channels of
// the supplied colors are also taken into account, so the returned color may
// be partially transparent.
-GFX_EXPORT SkColor AlphaBlend(SkColor foreground, SkColor background,
+GFX_EXPORT SkColor AlphaBlend(SkColor foreground,
+ SkColor background,
SkAlpha alpha);
+// As above, but with alpha specified as 0..1.
+GFX_EXPORT SkColor AlphaBlend(SkColor foreground,
+ SkColor background,
+ float alpha);
+
// Returns the color that results from painting |foreground| on top of
// |background|.
GFX_EXPORT SkColor GetResultingPaintColor(SkColor foreground,
SkColor background);
-// Returns true if the luma of |color| is closer to black than white.
+// Returns true if |color| contrasts more with white than the darkest color.
GFX_EXPORT bool IsDark(SkColor color);
-// Makes a dark color lighter or a light color darker by blending |color| with
-// white or black depending on its current luma. |alpha| controls the amount of
-// white or black that will be alpha-blended into |color|.
-GFX_EXPORT SkColor BlendTowardOppositeLuma(SkColor color, SkAlpha alpha);
-
-// This is a copy of |getThemedAssetColor()| in ColorUtils.java.
-GFX_EXPORT SkColor GetThemedAssetColor(SkColor theme_color);
+// Returns whichever of white or the darkest available color contrasts more with
+// |color|.
+GFX_EXPORT SkColor GetColorWithMaxContrast(SkColor color);
-// Given a foreground and background color, try to return a foreground color
-// that is "readable" over the background color by luma-inverting the foreground
-// color and then using PickContrastingColor() to pick the one with greater
-// contrast. During this process, alpha values will be ignored; the returned
-// color will have the same alpha as |foreground|.
-//
-// NOTE: This won't do anything but waste time if the supplied foreground color
-// has a luma value close to the midpoint (0.5 in the HSL representation).
-GFX_EXPORT SkColor GetReadableColor(SkColor foreground, SkColor background);
+// Blends towards the color with max contrast by |alpha|. The alpha of
+// the original color is preserved.
+GFX_EXPORT SkColor BlendTowardMaxContrast(SkColor color, SkAlpha alpha);
// Returns whichever of |foreground1| or |foreground2| has higher contrast with
// |background|.
@@ -185,11 +182,12 @@ GFX_EXPORT std::string SkColorToRgbaString(SkColor color);
// Creates an rgb string for an SkColor. For example: '255,0,255'.
GFX_EXPORT std::string SkColorToRgbString(SkColor color);
-// Sets the color_utils darkest color to |color| from the SK_ColorBLACK default.
-GFX_EXPORT void SetDarkestColor(SkColor color);
+// Sets the darkest available color to |color|. Returns the previous darkest
+// color.
+GFX_EXPORT SkColor SetDarkestColorForTesting(SkColor color);
-// Returns the current color_utils darkest color so tests can clean up.
-GFX_EXPORT SkColor GetDarkestColor();
+// Returns the luminance of the darkest, midpoint, and lightest colors.
+GFX_EXPORT std::tuple<float, float, float> GetLuminancesForTesting();
} // namespace color_utils
diff --git a/chromium/ui/gfx/color_utils_unittest.cc b/chromium/ui/gfx/color_utils_unittest.cc
index bb39cacb219..9fcedd363b8 100644
--- a/chromium/ui/gfx/color_utils_unittest.cc
+++ b/chromium/ui/gfx/color_utils_unittest.cc
@@ -9,6 +9,7 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColorPriv.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/rect.h"
@@ -180,16 +181,16 @@ TEST(ColorUtils, AlphaBlend) {
SkColor fore = SkColorSetARGB(255, 200, 200, 200);
SkColor back = SkColorSetARGB(255, 100, 100, 100);
- EXPECT_TRUE(AlphaBlend(fore, back, 255) == fore);
- EXPECT_TRUE(AlphaBlend(fore, back, 0) == back);
+ EXPECT_TRUE(AlphaBlend(fore, back, 1.0f) == fore);
+ EXPECT_TRUE(AlphaBlend(fore, back, 0.0f) == back);
// One is fully transparent, result is partially transparent.
back = SkColorSetA(back, 0);
- EXPECT_EQ(136U, SkColorGetA(AlphaBlend(fore, back, 136)));
+ EXPECT_EQ(136U, SkColorGetA(AlphaBlend(fore, back, SkAlpha{136})));
// Both are fully transparent, result is fully transparent.
fore = SkColorSetA(fore, 0);
- EXPECT_EQ(0U, SkColorGetA(AlphaBlend(fore, back, 255)));
+ EXPECT_EQ(0U, SkColorGetA(AlphaBlend(fore, back, 1.0f)));
}
TEST(ColorUtils, SkColorToRgbaString) {
@@ -205,13 +206,37 @@ TEST(ColorUtils, SkColorToRgbString) {
}
TEST(ColorUtils, IsDarkDarkestColorChange) {
- SkColor old_black_color = GetDarkestColor();
+ ASSERT_FALSE(IsDark(SK_ColorLTGRAY));
+ const SkColor old_darkest_color = SetDarkestColorForTesting(SK_ColorLTGRAY);
+ EXPECT_TRUE(IsDark(SK_ColorLTGRAY));
- ASSERT_FALSE(IsDark(SkColorSetARGB(255, 200, 200, 200)));
- SetDarkestColor(SkColorSetARGB(255, 200, 200, 200));
- EXPECT_TRUE(IsDark(SkColorSetARGB(255, 200, 200, 200)));
+ SetDarkestColorForTesting(old_darkest_color);
+}
+
+TEST(ColorUtils, MidpointLuminanceMatches) {
+ const SkColor old_darkest_color = SetDarkestColorForTesting(SK_ColorBLACK);
+ float darkest, midpoint, lightest;
+ std::tie(darkest, midpoint, lightest) = GetLuminancesForTesting();
+ EXPECT_FLOAT_EQ(GetContrastRatio(darkest, midpoint),
+ GetContrastRatio(midpoint, lightest));
+
+ SetDarkestColorForTesting(old_darkest_color);
+ std::tie(darkest, midpoint, lightest) = GetLuminancesForTesting();
+ EXPECT_FLOAT_EQ(GetContrastRatio(darkest, midpoint),
+ GetContrastRatio(midpoint, lightest));
+}
+
+TEST(ColorUtils, GetColorWithMaxContrast) {
+ const SkColor old_darkest_color = SetDarkestColorForTesting(SK_ColorBLACK);
+ EXPECT_EQ(SK_ColorWHITE, GetColorWithMaxContrast(SK_ColorBLACK));
+ EXPECT_EQ(SK_ColorWHITE,
+ GetColorWithMaxContrast(SkColorSetRGB(0x75, 0x75, 0x75)));
+ EXPECT_EQ(SK_ColorBLACK, GetColorWithMaxContrast(SK_ColorWHITE));
+ EXPECT_EQ(SK_ColorBLACK,
+ GetColorWithMaxContrast(SkColorSetRGB(0x76, 0x76, 0x76)));
- SetDarkestColor(old_black_color);
+ SetDarkestColorForTesting(old_darkest_color);
+ EXPECT_EQ(old_darkest_color, GetColorWithMaxContrast(SK_ColorWHITE));
}
TEST(ColorUtils, GetColorWithMinimumContrast_ForegroundAlreadyMeetsMinimum) {
@@ -236,15 +261,13 @@ TEST(ColorUtils, GetColorWithMinimumContrast_BlendLighter) {
}
TEST(ColorUtils, GetColorWithMinimumContrast_StopsAtDarkestColor) {
- SkColor old_black_color = GetDarkestColor();
-
const SkColor darkest_color = SkColorSetRGB(0x44, 0x44, 0x44);
- SetDarkestColor(darkest_color);
+ const SkColor old_darkest_color = SetDarkestColorForTesting(darkest_color);
EXPECT_EQ(darkest_color,
GetColorWithMinimumContrast(SkColorSetRGB(0x55, 0x55, 0x55),
SkColorSetRGB(0xAA, 0xAA, 0xAA)));
- SetDarkestColor(old_black_color);
+ SetDarkestColorForTesting(old_darkest_color);
}
TEST(ColorUtils, GetBlendValueWithMinimumContrast_ComputesExpectedOpacities) {
@@ -259,6 +282,28 @@ TEST(ColorUtils, GetBlendValueWithMinimumContrast_ComputesExpectedOpacities) {
EXPECT_NEAR(alpha / 255.0f, 0.45f, 0.03f);
}
+TEST(ColorUtils, BlendTowardMaxContrast_PreservesAlpha) {
+ SkColor test_colors[] = {SK_ColorBLACK, SK_ColorWHITE,
+ SK_ColorRED, SK_ColorYELLOW,
+ SK_ColorMAGENTA, gfx::kGoogleGreen500,
+ gfx::kGoogleRed050, gfx::kGoogleBlue800};
+ SkAlpha test_alphas[] = {SK_AlphaTRANSPARENT, 0x0F,
+ gfx::kDisabledControlAlpha, 0xDD};
+ SkAlpha blend_alpha = 0x7F;
+ for (const SkColor color : test_colors) {
+ SkColor opaque_result =
+ color_utils::BlendTowardMaxContrast(color, blend_alpha);
+ for (const SkAlpha alpha : test_alphas) {
+ SkColor input = SkColorSetA(color, alpha);
+ SkColor result = color_utils::BlendTowardMaxContrast(input, blend_alpha);
+ // Alpha was preserved.
+ EXPECT_EQ(SkColorGetA(result), alpha);
+ // RGB channels unaffected by alpha of input.
+ EXPECT_EQ(SkColorSetA(result, SK_AlphaOPAQUE), opaque_result);
+ }
+ }
+}
+
TEST(ColorUtils, FindBlendValueForContrastRatio_MatchesNaiveImplementation) {
const SkColor source = SkColorSetRGB(0xDE, 0xE1, 0xE6);
const SkColor target = SkColorSetRGB(0xFF, 0xFF, 0xFF);
diff --git a/chromium/ui/gfx/font_fallback_mac.mm b/chromium/ui/gfx/font_fallback_mac.mm
index 6a4d66f1d40..071b59fd781 100644
--- a/chromium/ui/gfx/font_fallback_mac.mm
+++ b/chromium/ui/gfx/font_fallback_mac.mm
@@ -60,10 +60,10 @@ std::vector<Font> GetFallbackFonts(const Font& font) {
CTFontDescriptorRef descriptor =
base::mac::CFCastStrict<CTFontDescriptorRef>(
CFArrayGetValueAtIndex(cascade_list, i));
- base::ScopedCFTypeRef<CTFontRef> font(
+ base::ScopedCFTypeRef<CTFontRef> fallback_font(
CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr));
- if (font.get())
- fallback_fonts.push_back(Font(static_cast<NSFont*>(font.get())));
+ if (fallback_font.get())
+ fallback_fonts.push_back(Font(static_cast<NSFont*>(fallback_font.get())));
}
if (fallback_fonts.empty())
diff --git a/chromium/ui/gfx/font_fallback_win.cc b/chromium/ui/gfx/font_fallback_win.cc
index 3da6eee3039..6d6fe87b26a 100644
--- a/chromium/ui/gfx/font_fallback_win.cc
+++ b/chromium/ui/gfx/font_fallback_win.cc
@@ -111,10 +111,10 @@ void QueryLinkedFontsFromRegistry(const Font& font,
if (!font_name.empty()) {
AppendFont(font_name, font.GetFontSize(), linked_fonts);
} else if (!filename.empty()) {
- std::vector<std::string> font_names;
- GetFontNamesFromFilename(filename, font_map, &font_names);
- for (size_t i = 0; i < font_names.size(); ++i)
- AppendFont(font_names[i], font.GetFontSize(), linked_fonts);
+ std::vector<std::string> filename_fonts;
+ GetFontNamesFromFilename(filename, font_map, &filename_fonts);
+ for (const std::string& filename_font : filename_fonts)
+ AppendFont(filename_font, font.GetFontSize(), linked_fonts);
}
}
diff --git a/chromium/ui/gfx/gdi_util.h b/chromium/ui/gfx/gdi_util.h
index 2e6d012aa0e..82afffea227 100644
--- a/chromium/ui/gfx/gdi_util.h
+++ b/chromium/ui/gfx/gdi_util.h
@@ -10,7 +10,6 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/path.h"
namespace gfx {
diff --git a/chromium/ui/gfx/generic_shared_memory_id.h b/chromium/ui/gfx/generic_shared_memory_id.h
index ed77e529a40..1db8acdc909 100644
--- a/chromium/ui/gfx/generic_shared_memory_id.h
+++ b/chromium/ui/gfx/generic_shared_memory_id.h
@@ -8,7 +8,6 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/containers/hash_tables.h"
#include "base/hash.h"
#include "base/trace_event/memory_allocator_dump.h"
#include "ui/gfx/gfx_export.h"
@@ -49,12 +48,12 @@ GetGenericSharedGpuMemoryGUIDForTracing(
} // namespace gfx
-namespace BASE_HASH_NAMESPACE {
+namespace std {
template <>
struct hash<gfx::GenericSharedMemoryId> {
size_t operator()(gfx::GenericSharedMemoryId key) const {
- return BASE_HASH_NAMESPACE::hash<int>()(key.id);
+ return std::hash<int>()(key.id);
}
};
@@ -66,6 +65,6 @@ struct hash<std::pair<gfx::GenericSharedMemoryId, Second>> {
}
};
-} // namespace BASE_HASH_NAMESPACE
+} // namespace std
#endif // UI_GFX_GENERIC_SHARED_MEMORY_ID_H_
diff --git a/chromium/ui/gfx/geometry/point.cc b/chromium/ui/gfx/geometry/point.cc
index 285b208d44c..883cb4bd2c6 100644
--- a/chromium/ui/gfx/geometry/point.cc
+++ b/chromium/ui/gfx/geometry/point.cc
@@ -34,7 +34,7 @@ Point& Point::operator=(const POINT& point) {
y_ = point.y;
return *this;
}
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
Point::Point(const CGPoint& point) : x_(point.x), y_(point.y) {
}
#endif
@@ -46,7 +46,7 @@ POINT Point::ToPOINT() const {
p.y = y();
return p;
}
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
CGPoint Point::ToCGPoint() const {
return CGPointMake(x(), y());
}
diff --git a/chromium/ui/gfx/geometry/point.h b/chromium/ui/gfx/geometry/point.h
index f68433b9065..c7a1649665f 100644
--- a/chromium/ui/gfx/geometry/point.h
+++ b/chromium/ui/gfx/geometry/point.h
@@ -17,7 +17,7 @@
#if defined(OS_WIN)
typedef unsigned long DWORD;
typedef struct tagPOINT POINT;
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
typedef struct CGPoint CGPoint;
#endif
@@ -35,13 +35,13 @@ class GEOMETRY_EXPORT Point {
explicit Point(DWORD point);
explicit Point(const POINT& point);
Point& operator=(const POINT& point);
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
explicit Point(const CGPoint& point);
#endif
#if defined(OS_WIN)
POINT ToPOINT() const;
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
CGPoint ToCGPoint() const;
#endif
diff --git a/chromium/ui/gfx/geometry/point3_unittest.cc b/chromium/ui/gfx/geometry/point3_unittest.cc
index 999b1f43c88..76b41ef94c8 100644
--- a/chromium/ui/gfx/geometry/point3_unittest.cc
+++ b/chromium/ui/gfx/geometry/point3_unittest.cc
@@ -4,7 +4,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/point3_f.h"
@@ -28,7 +28,7 @@ TEST(Point3Test, VectorArithmetic) {
{ gfx::Point3F(-9.6f, 9.5f, -2.8f), a - v1 + v2 }
};
- for (size_t i = 0; i < arraysize(tests); ++i)
+ for (size_t i = 0; i < base::size(tests); ++i)
EXPECT_EQ(tests[i].expected.ToString(),
tests[i].actual.ToString());
diff --git a/chromium/ui/gfx/geometry/point_unittest.cc b/chromium/ui/gfx/geometry/point_unittest.cc
index b453dd76842..33f7f3b91b1 100644
--- a/chromium/ui/gfx/geometry/point_unittest.cc
+++ b/chromium/ui/gfx/geometry/point_unittest.cc
@@ -4,7 +4,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_conversions.h"
@@ -57,7 +57,7 @@ TEST(PointTest, VectorArithmetic) {
{ Point(-10, 9), a - v1 + v2 }
};
- for (size_t i = 0; i < arraysize(tests); ++i)
+ for (size_t i = 0; i < base::size(tests); ++i)
EXPECT_EQ(tests[i].expected.ToString(), tests[i].actual.ToString());
}
diff --git a/chromium/ui/gfx/geometry/quad_unittest.cc b/chromium/ui/gfx/geometry/quad_unittest.cc
index 2731583aab8..cf57bdcc315 100644
--- a/chromium/ui/gfx/geometry/quad_unittest.cc
+++ b/chromium/ui/gfx/geometry/quad_unittest.cc
@@ -4,7 +4,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -153,7 +153,7 @@ TEST(QuadTest, IsRectilinear) {
}
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
PointF a_off = tests[i].a_off;
PointF b_off = tests[i].b_off;
PointF c_off = tests[i].c_off;
diff --git a/chromium/ui/gfx/geometry/quaternion_unittest.cc b/chromium/ui/gfx/geometry/quaternion_unittest.cc
index 5c8fa9b8aed..d350e26f523 100644
--- a/chromium/ui/gfx/geometry/quaternion_unittest.cc
+++ b/chromium/ui/gfx/geometry/quaternion_unittest.cc
@@ -6,7 +6,7 @@
#include <cmath>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/quaternion.h"
#include "ui/gfx/geometry/vector3d_f.h"
@@ -55,7 +55,7 @@ TEST(QuatTest, AxisAngleWithZeroLengthAxis) {
TEST(QuatTest, Addition) {
double values[] = {0, 1, 100};
- for (size_t i = 0; i < arraysize(values); ++i) {
+ for (size_t i = 0; i < base::size(values); ++i) {
float t = values[i];
Quaternion a(t, 2 * t, 3 * t, 4 * t);
Quaternion b(5 * t, 4 * t, 3 * t, 2 * t);
@@ -80,7 +80,7 @@ TEST(QuatTest, Multiplication) {
Quaternion(32, 32, 56, -6)},
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
Quaternion product = cases[i].a * cases[i].b;
CompareQuaternions(cases[i].expected, product);
}
@@ -88,7 +88,7 @@ TEST(QuatTest, Multiplication) {
TEST(QuatTest, Scaling) {
double values[] = {0, 10, 100};
- for (size_t i = 0; i < arraysize(values); ++i) {
+ for (size_t i = 0; i < base::size(values); ++i) {
double s = values[i];
Quaternion q(1, 2, 3, 4);
Quaternion expected(s, 2 * s, 3 * s, 4 * s);
diff --git a/chromium/ui/gfx/geometry/rect.cc b/chromium/ui/gfx/geometry/rect.cc
index dd51fd47d61..635e1695268 100644
--- a/chromium/ui/gfx/geometry/rect.cc
+++ b/chromium/ui/gfx/geometry/rect.cc
@@ -27,7 +27,7 @@ Rect::Rect(const RECT& r)
: origin_(r.left, r.top),
size_(std::abs(r.right - r.left), std::abs(r.bottom - r.top)) {
}
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
Rect::Rect(const CGRect& r)
: origin_(r.origin.x, r.origin.y), size_(r.size.width, r.size.height) {
}
@@ -42,7 +42,7 @@ RECT Rect::ToRECT() const {
r.bottom = bottom();
return r;
}
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
CGRect Rect::ToCGRect() const {
return CGRectMake(x(), y(), width(), height());
}
diff --git a/chromium/ui/gfx/geometry/rect.h b/chromium/ui/gfx/geometry/rect.h
index 84dc72c069c..7fa7045f6f4 100644
--- a/chromium/ui/gfx/geometry/rect.h
+++ b/chromium/ui/gfx/geometry/rect.h
@@ -25,7 +25,7 @@
#if defined(OS_WIN)
typedef struct tagRECT RECT;
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
typedef struct CGRect CGRect;
#endif
@@ -48,14 +48,14 @@ class GEOMETRY_EXPORT Rect {
#if defined(OS_WIN)
explicit Rect(const RECT& r);
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
explicit Rect(const CGRect& r);
#endif
#if defined(OS_WIN)
// Construct an equivalent Win32 RECT object.
RECT ToRECT() const;
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
// Construct an equivalent CoreGraphics object.
CGRect ToCGRect() const;
#endif
diff --git a/chromium/ui/gfx/geometry/rect_f.cc b/chromium/ui/gfx/geometry/rect_f.cc
index eb657858a5f..9159bb19a2a 100644
--- a/chromium/ui/gfx/geometry/rect_f.cc
+++ b/chromium/ui/gfx/geometry/rect_f.cc
@@ -32,7 +32,7 @@ static void AdjustAlongAxis(float dst_origin,
*origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
}
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_IOS)
RectF::RectF(const CGRect& r)
: origin_(r.origin.x, r.origin.y), size_(r.size.width, r.size.height) {
}
diff --git a/chromium/ui/gfx/geometry/rect_f.h b/chromium/ui/gfx/geometry/rect_f.h
index e07f86d50db..81abb8c46af 100644
--- a/chromium/ui/gfx/geometry/rect_f.h
+++ b/chromium/ui/gfx/geometry/rect_f.h
@@ -14,7 +14,7 @@
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_IOS)
typedef struct CGRect CGRect;
#endif
@@ -39,7 +39,7 @@ class GEOMETRY_EXPORT RectF {
static_cast<float>(r.width()),
static_cast<float>(r.height())) {}
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_IOS)
explicit RectF(const CGRect& r);
// Construct an equivalent CoreGraphics object.
CGRect ToCGRect() const;
diff --git a/chromium/ui/gfx/geometry/scroll_offset_unittest.cc b/chromium/ui/gfx/geometry/scroll_offset_unittest.cc
index 782fdf4c10d..4ad3460b106 100644
--- a/chromium/ui/gfx/geometry/scroll_offset_unittest.cc
+++ b/chromium/ui/gfx/geometry/scroll_offset_unittest.cc
@@ -7,7 +7,7 @@
#include <cmath>
#include <limits>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/scroll_offset.h"
@@ -34,7 +34,7 @@ TEST(ScrollOffsetTest, Add) {
{ ScrollOffset(3.1f - 4.3f, 5.1f + 1.3f), f1 - f2 }
};
- for (size_t i = 0; i < arraysize(scroll_offset_tests); ++i)
+ for (size_t i = 0; i < base::size(scroll_offset_tests); ++i)
EXPECT_EQ(scroll_offset_tests[i].expected.ToString(),
scroll_offset_tests[i].actual.ToString());
}
@@ -50,7 +50,7 @@ TEST(ScrollOffsetTest, Negative) {
{ ScrollOffset(0.3f, -0.3f), -ScrollOffset(-0.3f, 0.3f) }
};
- for (size_t i = 0; i < arraysize(scroll_offset_tests); ++i)
+ for (size_t i = 0; i < base::size(scroll_offset_tests); ++i)
EXPECT_EQ(scroll_offset_tests[i].expected.ToString(),
scroll_offset_tests[i].actual.ToString());
}
@@ -68,7 +68,7 @@ TEST(ScrollOffsetTest, Scale) {
{ 0, 1.2f, 3.3f, 5.6f }
};
- for (size_t i = 0; i < arraysize(float_values); ++i) {
+ for (size_t i = 0; i < base::size(float_values); ++i) {
ScrollOffset v(float_values[i][0], float_values[i][1]);
v.Scale(float_values[i][2], float_values[i][3]);
EXPECT_EQ(v.x(), float_values[i][0] * float_values[i][2]);
@@ -87,7 +87,7 @@ TEST(ScrollOffsetTest, Scale) {
{ 0, 1.2f, 3.3f }
};
- for (size_t i = 0; i < arraysize(single_values); ++i) {
+ for (size_t i = 0; i < base::size(single_values); ++i) {
ScrollOffset v(single_values[i][0], single_values[i][1]);
v.Scale(single_values[i][2]);
EXPECT_EQ(v.x(), single_values[i][0] * single_values[i][2]);
diff --git a/chromium/ui/gfx/geometry/size.cc b/chromium/ui/gfx/geometry/size.cc
index 781b84d7f51..35aba45d726 100644
--- a/chromium/ui/gfx/geometry/size.cc
+++ b/chromium/ui/gfx/geometry/size.cc
@@ -21,7 +21,7 @@
namespace gfx {
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_IOS)
Size::Size(const CGSize& s)
: width_(s.width < 0 ? 0 : s.width),
height_(s.height < 0 ? 0 : s.height) {
@@ -41,7 +41,7 @@ SIZE Size::ToSIZE() const {
s.cy = height();
return s;
}
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
CGSize Size::ToCGSize() const {
return CGSizeMake(width(), height());
}
diff --git a/chromium/ui/gfx/geometry/size.h b/chromium/ui/gfx/geometry/size.h
index 03490b5ab81..c616b255c98 100644
--- a/chromium/ui/gfx/geometry/size.h
+++ b/chromium/ui/gfx/geometry/size.h
@@ -15,7 +15,7 @@
#if defined(OS_WIN)
typedef struct tagSIZE SIZE;
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
typedef struct CGSize CGSize;
#endif
@@ -27,17 +27,17 @@ class GEOMETRY_EXPORT Size {
constexpr Size() : width_(0), height_(0) {}
constexpr Size(int width, int height)
: width_(width < 0 ? 0 : width), height_(height < 0 ? 0 : height) {}
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_IOS)
explicit Size(const CGSize& s);
#endif
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_IOS)
Size& operator=(const CGSize& s);
#endif
#if defined(OS_WIN)
SIZE ToSIZE() const;
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) || defined(OS_IOS)
CGSize ToCGSize() const;
#endif
diff --git a/chromium/ui/gfx/geometry/vector2d_unittest.cc b/chromium/ui/gfx/geometry/vector2d_unittest.cc
index 4bdf24cba4a..8f49a8b52db 100644
--- a/chromium/ui/gfx/geometry/vector2d_unittest.cc
+++ b/chromium/ui/gfx/geometry/vector2d_unittest.cc
@@ -7,7 +7,7 @@
#include <cmath>
#include <limits>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/geometry/vector2d_f.h"
@@ -45,7 +45,7 @@ TEST(Vector2dTest, Add) {
{ Vector2d(3 - 4, 5 + 1), i1 - i2 }
};
- for (size_t i = 0; i < arraysize(int_tests); ++i)
+ for (size_t i = 0; i < base::size(int_tests); ++i)
EXPECT_EQ(int_tests[i].expected.ToString(),
int_tests[i].actual.ToString());
@@ -62,7 +62,7 @@ TEST(Vector2dTest, Add) {
{ Vector2dF(3.1f - 4.3f, 5.1f + 1.3f), f1 - f2 }
};
- for (size_t i = 0; i < arraysize(float_tests); ++i)
+ for (size_t i = 0; i < base::size(float_tests); ++i)
EXPECT_EQ(float_tests[i].expected.ToString(),
float_tests[i].actual.ToString());
}
@@ -79,7 +79,7 @@ TEST(Vector2dTest, Negative) {
{ Vector2d(3, -3), -Vector2d(-3, 3) }
};
- for (size_t i = 0; i < arraysize(int_tests); ++i)
+ for (size_t i = 0; i < base::size(int_tests); ++i)
EXPECT_EQ(int_tests[i].expected.ToString(),
int_tests[i].actual.ToString());
@@ -94,7 +94,7 @@ TEST(Vector2dTest, Negative) {
{ Vector2dF(0.3f, -0.3f), -Vector2dF(-0.3f, 0.3f) }
};
- for (size_t i = 0; i < arraysize(float_tests); ++i)
+ for (size_t i = 0; i < base::size(float_tests); ++i)
EXPECT_EQ(float_tests[i].expected.ToString(),
float_tests[i].actual.ToString());
}
@@ -112,7 +112,7 @@ TEST(Vector2dTest, Scale) {
{ 0, 1.2f, 3.3f, 5.6f }
};
- for (size_t i = 0; i < arraysize(double_values); ++i) {
+ for (size_t i = 0; i < base::size(double_values); ++i) {
Vector2dF v(double_values[i][0], double_values[i][1]);
v.Scale(double_values[i][2], double_values[i][3]);
EXPECT_EQ(v.x(), double_values[i][0] * double_values[i][2]);
@@ -137,7 +137,7 @@ TEST(Vector2dTest, Scale) {
{ 0, 1.2f, 3.3f }
};
- for (size_t i = 0; i < arraysize(single_values); ++i) {
+ for (size_t i = 0; i < base::size(single_values); ++i) {
Vector2dF v(single_values[i][0], single_values[i][1]);
v.Scale(single_values[i][2]);
EXPECT_EQ(v.x(), single_values[i][0] * single_values[i][2]);
@@ -161,7 +161,7 @@ TEST(Vector2dTest, Length) {
{ 10, -20 },
};
- for (size_t i = 0; i < arraysize(int_values); ++i) {
+ for (size_t i = 0; i < base::size(int_values); ++i) {
int v0 = int_values[i][0];
int v1 = int_values[i][1];
double length_squared =
@@ -185,7 +185,7 @@ TEST(Vector2dTest, Length) {
335890352589839028212313231225425134332.38123f },
};
- for (size_t i = 0; i < arraysize(float_values); ++i) {
+ for (size_t i = 0; i < base::size(float_values); ++i) {
double v0 = float_values[i][0];
double v1 = float_values[i][1];
double length_squared =
diff --git a/chromium/ui/gfx/geometry/vector3d_f.cc b/chromium/ui/gfx/geometry/vector3d_f.cc
index 749e330f273..d538a57f0d7 100644
--- a/chromium/ui/gfx/geometry/vector3d_f.cc
+++ b/chromium/ui/gfx/geometry/vector3d_f.cc
@@ -86,8 +86,11 @@ Vector3dF ScaleVector3d(const Vector3dF& v,
float AngleBetweenVectorsInDegrees(const gfx::Vector3dF& base,
const gfx::Vector3dF& other) {
- return gfx::RadToDeg(
- std::acos(gfx::DotProduct(base, other) / base.Length() / other.Length()));
+ // Clamp the resulting value to prevent potential NANs from floating point
+ // precision issues.
+ return gfx::RadToDeg(std::acos(fmax(
+ fmin(gfx::DotProduct(base, other) / base.Length() / other.Length(), 1.f),
+ -1.f)));
}
float ClockwiseAngleBetweenVectorsInDegrees(const gfx::Vector3dF& base,
diff --git a/chromium/ui/gfx/geometry/vector3d_unittest.cc b/chromium/ui/gfx/geometry/vector3d_unittest.cc
index 12ee7573467..9a7e8b68b5d 100644
--- a/chromium/ui/gfx/geometry/vector3d_unittest.cc
+++ b/chromium/ui/gfx/geometry/vector3d_unittest.cc
@@ -7,7 +7,7 @@
#include <cmath>
#include <limits>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/vector3d_f.h"
@@ -35,7 +35,7 @@ TEST(Vector3dTest, Add) {
{ gfx::Vector3dF(3.1f - 4.3f, 5.1f + 1.3f, 2.7f - 8.1f), f1 - f2 }
};
- for (size_t i = 0; i < arraysize(float_tests); ++i)
+ for (size_t i = 0; i < base::size(float_tests); ++i)
EXPECT_EQ(float_tests[i].expected.ToString(),
float_tests[i].actual.ToString());
}
@@ -53,7 +53,7 @@ TEST(Vector3dTest, Negative) {
{ gfx::Vector3dF(-0.3f, -0.3f, 0.3f), -gfx::Vector3dF(0.3f, 0.3f, -0.3f) }
};
- for (size_t i = 0; i < arraysize(float_tests); ++i)
+ for (size_t i = 0; i < base::size(float_tests); ++i)
EXPECT_EQ(float_tests[i].expected.ToString(),
float_tests[i].actual.ToString());
}
@@ -86,7 +86,7 @@ TEST(Vector3dTest, Scale) {
{ 0, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f }
};
- for (size_t i = 0; i < arraysize(triple_values); ++i) {
+ for (size_t i = 0; i < base::size(triple_values); ++i) {
gfx::Vector3dF v(triple_values[i][0],
triple_values[i][1],
triple_values[i][2]);
@@ -122,7 +122,7 @@ TEST(Vector3dTest, Scale) {
{ 4.5f, 1.2f, 0, 3.3f }
};
- for (size_t i = 0; i < arraysize(single_values); ++i) {
+ for (size_t i = 0; i < base::size(single_values); ++i) {
gfx::Vector3dF v(single_values[i][0],
single_values[i][1],
single_values[i][2]);
@@ -164,7 +164,7 @@ TEST(Vector3dTest, Length) {
27861786423846742743236423478236784678.236713617231f }
};
- for (size_t i = 0; i < arraysize(float_values); ++i) {
+ for (size_t i = 0; i < base::size(float_values); ++i) {
double v0 = float_values[i][0];
double v1 = float_values[i][1];
double v2 = float_values[i][2];
@@ -198,7 +198,7 @@ TEST(Vector3dTest, DotProduct) {
gfx::Vector3dF(1.1f, 2.2f, 3.3f), gfx::Vector3dF(4.4f, 5.5f, 6.6f) }
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
float actual = gfx::DotProduct(tests[i].input1, tests[i].input2);
EXPECT_EQ(tests[i].expected, actual);
}
@@ -226,7 +226,7 @@ TEST(Vector3dTest, CrossProduct) {
{ Vector3dF(0, -1, 1), Vector3dF(1, 0, 0), Vector3dF(1, 1, 1) }
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
SCOPED_TRACE(i);
Vector3dF actual = gfx::CrossProduct(tests[i].input1, tests[i].input2);
EXPECT_EQ(tests[i].expected.ToString(), actual.ToString());
@@ -270,16 +270,18 @@ TEST(Vector3dTest, AngleBetweenVectorsInDegress) {
float expected;
gfx::Vector3dF input1;
gfx::Vector3dF input2;
- } tests[] = {
- {0, gfx::Vector3dF(0, 1, 0), gfx::Vector3dF(0, 1, 0)},
- {90, gfx::Vector3dF(0, 1, 0), gfx::Vector3dF(0, 0, 1)},
- {45,
- gfx::Vector3dF(0, 1, 0),
- gfx::Vector3dF(0, 0.70710678188f, 0.70710678188f)},
- {180, gfx::Vector3dF(0, 1, 0), gfx::Vector3dF(0, -1, 0)},
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ } tests[] = {{0, gfx::Vector3dF(0, 1, 0), gfx::Vector3dF(0, 1, 0)},
+ {90, gfx::Vector3dF(0, 1, 0), gfx::Vector3dF(0, 0, 1)},
+ {45, gfx::Vector3dF(0, 1, 0),
+ gfx::Vector3dF(0, 0.70710678188f, 0.70710678188f)},
+ {180, gfx::Vector3dF(0, 1, 0), gfx::Vector3dF(0, -1, 0)},
+ // Two vectors that are sufficiently close enough together to
+ // trigger an issue that produces NANs if the value passed to
+ // acos is not clamped due to floating point precision.
+ {0, gfx::Vector3dF(0, -0.990842f, -0.003177f),
+ gfx::Vector3dF(0, -0.999995f, -0.003124f)}};
+
+ for (size_t i = 0; i < base::size(tests); ++i) {
float actual =
gfx::AngleBetweenVectorsInDegrees(tests[i].input1, tests[i].input2);
EXPECT_FLOAT_EQ(tests[i].expected, actual);
@@ -306,7 +308,7 @@ TEST(Vector3dTest, ClockwiseAngleBetweenVectorsInDegress) {
const gfx::Vector3dF normal_vector(1.0f, 0.0f, 0.0f);
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
float actual = gfx::ClockwiseAngleBetweenVectorsInDegrees(
tests[i].input1, tests[i].input2, normal_vector);
EXPECT_FLOAT_EQ(tests[i].expected, actual);
@@ -337,7 +339,7 @@ TEST(Vector3dTest, GetNormalized) {
gfx::Vector3dF(1, 0, 0)},
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
gfx::Vector3dF n;
EXPECT_EQ(tests[i].expected, tests[i].v.GetNormalized(&n));
EXPECT_EQ(tests[i].normalized.ToString(), n.ToString());
diff --git a/chromium/ui/gfx/half_float_unittest.cc b/chromium/ui/gfx/half_float_unittest.cc
index 5e7c61eb6ac..db693ff3102 100644
--- a/chromium/ui/gfx/half_float_unittest.cc
+++ b/chromium/ui/gfx/half_float_unittest.cc
@@ -4,7 +4,7 @@
#include <math.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/half_float.h"
@@ -75,7 +75,7 @@ TEST_F(HalfFloatTest, SimpleTest) {
0.0f, 1.0f, 10.0f, 1000.0f, 65503.0f,
1.0E-3f, 1.0E-6f, 1.0E-20f, 1.0E-44f,
};
- for (size_t i = 0; i < arraysize(test); i++) {
+ for (size_t i = 0; i < base::size(test); i++) {
EXPECT_EQ(ConvertTruth(test[i]), Convert(test[i])) << " float = "
<< test[i];
if (test[i] != 0.0) {
diff --git a/chromium/ui/gfx/harfbuzz_font_skia.cc b/chromium/ui/gfx/harfbuzz_font_skia.cc
index a06771b8b35..4c3fe3f10de 100644
--- a/chromium/ui/gfx/harfbuzz_font_skia.cc
+++ b/chromium/ui/gfx/harfbuzz_font_skia.cc
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/no_destructor.h"
#include "build/build_config.h"
+#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/render_text.h"
#include "ui/gfx/skia_util.h"
@@ -33,9 +34,9 @@ typedef std::pair<HarfBuzzFace, GlyphCache> FaceCache;
// Font data provider for HarfBuzz using Skia. Copied from Blink.
// TODO(ckocagil): Eliminate the duplication. http://crbug.com/368375
struct FontData {
- FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {}
+ explicit FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {}
- cc::PaintFlags flags_;
+ SkFont font_;
GlyphCache* glyph_cache_;
};
@@ -54,12 +55,10 @@ void DeleteArrayByType(void* data) {
// Outputs the |width| and |extents| of the glyph with index |codepoint| in
// |paint|'s font.
-void GetGlyphWidthAndExtents(cc::PaintFlags* flags,
+void GetGlyphWidthAndExtents(const SkFont& font,
hb_codepoint_t codepoint,
hb_position_t* width,
hb_glyph_extents_t* extents) {
- SkFont font = flags->ToSkFont();
-
DCHECK_LE(codepoint, std::numeric_limits<uint16_t>::max());
SkScalar sk_width;
@@ -91,10 +90,9 @@ hb_bool_t GetGlyph(hb_font_t* font,
GlyphCache* cache = font_data->glyph_cache_;
bool exists = cache->count(unicode) != 0;
- if (!exists) {
- (*cache)[unicode] =
- font_data->flags_.getTypeface()->unicharToGlyph(unicode);
- }
+ if (!exists)
+ (*cache)[unicode] = font_data->font_.unicharToGlyph(unicode);
+
*glyph = (*cache)[unicode];
return !!*glyph;
}
@@ -115,7 +113,7 @@ hb_position_t GetGlyphHorizontalAdvance(hb_font_t* font,
FontData* font_data = reinterpret_cast<FontData*>(data);
hb_position_t advance = 0;
- GetGlyphWidthAndExtents(&font_data->flags_, glyph, &advance, 0);
+ GetGlyphWidthAndExtents(font_data->font_, glyph, &advance, 0);
return advance;
}
@@ -132,7 +130,7 @@ hb_bool_t GetGlyphHorizontalOrigin(hb_font_t* font,
hb_position_t GetGlyphKerning(FontData* font_data,
hb_codepoint_t first_glyph,
hb_codepoint_t second_glyph) {
- SkTypeface* typeface = font_data->flags_.getTypeface().get();
+ SkTypeface* typeface = font_data->font_.getTypeface();
const uint16_t glyphs[2] = { static_cast<uint16_t>(first_glyph),
static_cast<uint16_t>(second_glyph) };
int32_t kerning_adjustments[1] = { 0 };
@@ -141,7 +139,7 @@ hb_position_t GetGlyphKerning(FontData* font_data,
return 0;
SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm());
- SkScalar size = font_data->flags_.getTextSize();
+ SkScalar size = font_data->font_.getSize();
return SkiaScalarToHarfBuzzUnits(SkIntToScalar(kerning_adjustments[0]) *
size / upm);
}
@@ -172,7 +170,7 @@ hb_bool_t GetGlyphExtents(hb_font_t* font,
void* user_data) {
FontData* font_data = reinterpret_cast<FontData*>(data);
- GetGlyphWidthAndExtents(&font_data->flags_, glyph, 0, extents);
+ GetGlyphWidthAndExtents(font_data->font_, glyph, 0, extents);
return true;
}
@@ -224,8 +222,9 @@ hb_blob_t* GetFontTable(hb_face_t* face, hb_tag_t tag, void* user_data) {
return 0;
char* buffer_raw = buffer.release();
- return hb_blob_create(buffer_raw, table_size, HB_MEMORY_MODE_WRITABLE,
- buffer_raw, DeleteArrayByType<char>);
+ return hb_blob_create(buffer_raw, static_cast<uint32_t>(table_size),
+ HB_MEMORY_MODE_WRITABLE, buffer_raw,
+ DeleteArrayByType<char>);
}
void UnrefSkTypeface(void* data) {
@@ -279,11 +278,11 @@ hb_font_t* CreateHarfBuzzFont(sk_sp<SkTypeface> skia_face,
const int scale = SkiaScalarToHarfBuzzUnits(text_size);
hb_font_set_scale(harfbuzz_font, scale, scale);
FontData* hb_font_data = new FontData(&face_cache->second);
- hb_font_data->flags_.setTypeface(std::move(skia_face));
- hb_font_data->flags_.setTextSize(text_size);
+ hb_font_data->font_.setTypeface(std::move(skia_face));
+ hb_font_data->font_.setSize(text_size);
// TODO(ckocagil): Do we need to update these params later?
internal::ApplyRenderParams(params, subpixel_rendering_suppressed,
- &hb_font_data->flags_);
+ &hb_font_data->font_);
hb_font_set_funcs(harfbuzz_font, g_font_funcs.Get().get(), hb_font_data,
DeleteByType<FontData>);
hb_font_make_immutable(harfbuzz_font);
diff --git a/chromium/ui/gfx/icc_profile.cc b/chromium/ui/gfx/icc_profile.cc
index 3fcef25f18c..6d9f7c5ac34 100644
--- a/chromium/ui/gfx/icc_profile.cc
+++ b/chromium/ui/gfx/icc_profile.cc
@@ -97,7 +97,7 @@ ICCProfile::Internals::AnalyzeResult ICCProfile::Internals::Initialize() {
DCHECK(sk_color_space_);
// Extract the primary matrix and transfer function
- to_XYZD50_.set3x3RowMajorf(&profile.toXYZD50.vals[0][0]);
+ to_XYZD50_ = profile.toXYZD50;
memcpy(&transfer_fn_, &profile.trc[0].parametric, sizeof(transfer_fn_));
// We assume that if we accurately approximated the profile, then the
diff --git a/chromium/ui/gfx/icc_profile.h b/chromium/ui/gfx/icc_profile.h
index f7d76e14aa8..027c8f2e859 100644
--- a/chromium/ui/gfx/icc_profile.h
+++ b/chromium/ui/gfx/icc_profile.h
@@ -103,7 +103,7 @@ class COLOR_SPACE_EXPORT ICCProfile {
sk_sp<SkColorSpace> sk_color_space_;
// The best-fit parametric primaries and transfer function.
- SkMatrix44 to_XYZD50_;
+ skcms_Matrix3x3 to_XYZD50_;
SkColorSpaceTransferFn transfer_fn_;
// The set of display ids which have have caused this ICC profile to be
diff --git a/chromium/ui/gfx/icon_util.cc b/chromium/ui/gfx/icon_util.cc
index d69e329ce81..1f226e888c3 100644
--- a/chromium/ui/gfx/icon_util.cc
+++ b/chromium/ui/gfx/icon_util.cc
@@ -4,12 +4,10 @@
#include "ui/gfx/icon_util.h"
-#include <memory>
-
#include "base/files/file_util.h"
#include "base/files/important_file_writer.h"
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "base/win/resource_util.h"
#include "base/win/scoped_gdi_object.h"
@@ -159,7 +157,7 @@ const int IconUtil::kIconDimensions[] = {
256 // Used by Vista onwards for large icons.
};
-const size_t IconUtil::kNumIconDimensions = arraysize(kIconDimensions);
+const size_t IconUtil::kNumIconDimensions = base::size(kIconDimensions);
const size_t IconUtil::kNumIconDimensionsUpToMediumSize = 9;
base::win::ScopedHICON IconUtil::CreateHICONFromSkBitmap(
@@ -476,9 +474,13 @@ bool IconUtil::CreateIconFileFromImageFamily(
// Guaranteed true because BuildResizedImageFamily will provide at least one
// image < 256x256.
DCHECK(!bitmaps.empty());
- size_t bitmap_count = bitmaps.size(); // Not including PNG image.
+ // ICONDIR's idCount is a WORD, so check for overflow.
+ DCHECK_LE(bitmaps.size(),
+ static_cast<size_t>(USHRT_MAX - (png_bytes.get() ? 1 : 0)));
+ WORD bitmap_count =
+ static_cast<WORD>(bitmaps.size()); // Not including PNG image.
// Including PNG image, if any.
- size_t image_count = bitmap_count + (png_bytes.get() ? 1 : 0);
+ WORD image_count = bitmap_count + (png_bytes.get() ? 1 : 0);
// Computing the total size of the buffer we need in order to store the
// images in the desired icon format.
@@ -494,11 +496,11 @@ bool IconUtil::CreateIconFileFromImageFamily(
std::vector<uint8_t> buffer(buffer_size);
ICONDIR* icon_dir = reinterpret_cast<ICONDIR*>(&buffer[0]);
icon_dir->idType = kResourceTypeIcon;
- icon_dir->idCount = static_cast<WORD>(image_count);
+ icon_dir->idCount = image_count;
// - 1 because there is already one ICONDIRENTRY in ICONDIR.
- size_t icon_dir_count = image_count - 1;
+ DWORD icon_dir_count = image_count - 1;
- size_t offset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY) * icon_dir_count);
+ DWORD offset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY) * icon_dir_count);
for (size_t i = 0; i < bitmap_count; i++) {
ICONIMAGE* image = reinterpret_cast<ICONIMAGE*>(&buffer[offset]);
DCHECK_LT(offset, buffer_size);
@@ -517,7 +519,7 @@ bool IconUtil::CreateIconFileFromImageFamily(
entry->wPlanes = 1;
entry->wBitCount = 32;
entry->dwBytesInRes = static_cast<DWORD>(png_bytes->size());
- entry->dwImageOffset = static_cast<DWORD>(offset);
+ entry->dwImageOffset = offset;
memcpy(&buffer[offset], png_bytes->front(), png_bytes->size());
offset += png_bytes->size();
}
@@ -583,7 +585,7 @@ void IconUtil::SetSingleIconImageInformation(const SkBitmap& bitmap,
size_t index,
ICONDIR* icon_dir,
ICONIMAGE* icon_image,
- size_t image_offset,
+ DWORD image_offset,
size_t* image_byte_count) {
DCHECK(icon_dir != NULL);
DCHECK(icon_image != NULL);
@@ -593,7 +595,8 @@ void IconUtil::SetSingleIconImageInformation(const SkBitmap& bitmap,
DCHECK_LT(bitmap.height(), kLargeIconSize);
// We start by computing certain image values we'll use later on.
- size_t xor_mask_size, bytes_in_resource;
+ size_t xor_mask_size;
+ DWORD bytes_in_resource;
ComputeBitmapSizeComponents(bitmap,
&xor_mask_size,
&bytes_in_resource);
@@ -663,7 +666,8 @@ size_t IconUtil::ComputeIconFileBufferSize(const std::vector<SkBitmap>& set) {
// Add the bitmap specific structure sizes.
for (size_t i = 0; i < bitmap_count; i++) {
- size_t xor_mask_size, bytes_in_resource;
+ size_t xor_mask_size;
+ DWORD bytes_in_resource;
ComputeBitmapSizeComponents(set[i],
&xor_mask_size,
&bytes_in_resource);
@@ -674,7 +678,7 @@ size_t IconUtil::ComputeIconFileBufferSize(const std::vector<SkBitmap>& set) {
void IconUtil::ComputeBitmapSizeComponents(const SkBitmap& bitmap,
size_t* xor_mask_size,
- size_t* bytes_in_resource) {
+ DWORD* bytes_in_resource) {
// The XOR mask size is easy to calculate since we only deal with 32bpp
// images.
*xor_mask_size = bitmap.width() * bitmap.height() * 4;
@@ -704,5 +708,6 @@ void IconUtil::ComputeBitmapSizeComponents(const SkBitmap& bitmap,
and_line_length = (and_line_length + 3) & ~3;
size_t and_mask_size = and_line_length * bitmap.height();
size_t masks_size = *xor_mask_size + and_mask_size;
- *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER);
+ *bytes_in_resource =
+ static_cast<DWORD>(masks_size + sizeof(BITMAPINFOHEADER));
}
diff --git a/chromium/ui/gfx/icon_util.h b/chromium/ui/gfx/icon_util.h
index 2d7d1abddc9..e2fcbd18b39 100644
--- a/chromium/ui/gfx/icon_util.h
+++ b/chromium/ui/gfx/icon_util.h
@@ -228,7 +228,7 @@ class GFX_EXPORT IconUtil {
size_t index,
ICONDIR* icon_dir,
ICONIMAGE* icon_image,
- size_t image_offset,
+ DWORD image_offset,
size_t* image_byte_count);
// Copies the bits of an SkBitmap object into a buffer holding the bits of
@@ -259,7 +259,7 @@ class GFX_EXPORT IconUtil {
// different size components.
static void ComputeBitmapSizeComponents(const SkBitmap& bitmap,
size_t* xor_mask_size,
- size_t* bytes_in_resource);
+ DWORD* bytes_in_resource);
// A helper function of CreateSkBitmapFromHICON.
static SkBitmap CreateSkBitmapFromHICONHelper(HICON icon,
diff --git a/chromium/ui/gfx/image/image.cc b/chromium/ui/gfx/image/image.cc
index 3fe6a6f5e50..8e2b0d9da75 100644
--- a/chromium/ui/gfx/image/image.cc
+++ b/chromium/ui/gfx/image/image.cc
@@ -368,11 +368,11 @@ Image::Image(NSImage* image) {
Image::Image(const Image& other) = default;
-Image::Image(Image&& other) = default;
+Image::Image(Image&& other) noexcept = default;
Image& Image::operator=(const Image& other) = default;
-Image& Image::operator=(Image&& other) = default;
+Image& Image::operator=(Image&& other) noexcept = default;
Image::~Image() {}
diff --git a/chromium/ui/gfx/image/image.h b/chromium/ui/gfx/image/image.h
index e33e5359692..d2dbcd28628 100644
--- a/chromium/ui/gfx/image/image.h
+++ b/chromium/ui/gfx/image/image.h
@@ -80,14 +80,14 @@ class GFX_EXPORT Image {
// Moves a reference from |other| to the new image without changing the
// reference count.
- Image(Image&& other);
+ Image(Image&& other) noexcept;
// Copies a reference to |other|'s storage.
Image& operator=(const Image& other);
// Moves a reference from |other|'s storage without changing the reference
// count.
- Image& operator=(Image&& other);
+ Image& operator=(Image&& other) noexcept;
// Deletes the image and, if the only owner of the storage, all of its cached
// representations.
diff --git a/chromium/ui/gfx/image/image_ios_unittest.mm b/chromium/ui/gfx/image/image_ios_unittest.mm
index 1e8c5e8b3e6..2ad17170c25 100644
--- a/chromium/ui/gfx/image/image_ios_unittest.mm
+++ b/chromium/ui/gfx/image/image_ios_unittest.mm
@@ -8,7 +8,7 @@
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
@@ -72,8 +72,8 @@ TEST_F(ImageIOSTest, ImageConversionWithUnsupportedScaleFactor) {
const CGFloat kHeight = 100;
const CGFloat kTestScales[3] = { 1.0f, 2.0f, 3.0f };
- for (size_t i = 0; i < arraysize(kTestScales); ++i) {
- for (size_t j = 0; j < arraysize(kTestScales); ++j) {
+ for (size_t i = 0; i < base::size(kTestScales); ++i) {
+ for (size_t j = 0; j < base::size(kTestScales); ++j) {
const CGFloat source_scale = kTestScales[i];
const CGFloat supported_scale = kTestScales[j];
diff --git a/chromium/ui/gfx/ios/uikit_util_unittest.mm b/chromium/ui/gfx/ios/uikit_util_unittest.mm
index f6cf49db54c..61d024c205b 100644
--- a/chromium/ui/gfx/ios/uikit_util_unittest.mm
+++ b/chromium/ui/gfx/ios/uikit_util_unittest.mm
@@ -5,7 +5,7 @@
#import <Foundation/Foundation.h>
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/platform_test.h"
#import "ui/gfx/ios/uikit_util.h"
@@ -20,7 +20,7 @@ TEST_F(UIKitUtilTest, AlignValueToUpperPixel) {
// "integer" values within <1 of the original value in the scaled space.
CGFloat test_values[] = { 10.0, 55.5, 3.1, 2.9 };
const CGFloat kMaxAlignDelta = 0.9999;
- size_t value_count = arraysize(test_values);
+ size_t value_count = base::size(test_values);
for (unsigned int i = 0; i < value_count; ++i) {
CGFloat aligned = ui::AlignValueToUpperPixel(test_values[i]);
EXPECT_FLOAT_EQ(aligned * scale, floor(aligned * scale));
@@ -35,7 +35,7 @@ TEST_F(UIKitUtilTest, AlignSizeToUpperPixel) {
// "integer" values within <1 of the original value in the scaled space.
CGFloat test_values[] = { 10.0, 55.5, 3.1, 2.9 };
const CGFloat kMaxAlignDelta = 0.9999;
- size_t value_count = arraysize(test_values);
+ size_t value_count = base::size(test_values);
for (unsigned int i = 0; i < value_count; ++i) {
CGFloat width = test_values[i];
CGFloat height = test_values[(i + 1) % value_count];
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
index 0a8ecf0f74e..76f6b0bd506 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
+++ b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
@@ -63,6 +63,17 @@ void PrimeSyncEnd(int dmabuf_fd) {
bool ClientNativePixmapDmaBuf::IsConfigurationSupported(
gfx::BufferFormat format,
gfx::BufferUsage usage) {
+#if defined(CHROMECAST_BUILD)
+ switch (usage) {
+ case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
+ case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
+ // TODO(spang): Fix b/121148905 and turn these back on.
+ return false;
+ default:
+ break;
+ }
+#endif
+
switch (usage) {
case gfx::BufferUsage::GPU_READ:
return format == gfx::BufferFormat::BGR_565 ||
diff --git a/chromium/ui/gfx/mac/io_surface.cc b/chromium/ui/gfx/mac/io_surface.cc
index 8d9f38b1f3d..d12f8a42cb6 100644
--- a/chromium/ui/gfx/mac/io_surface.cc
+++ b/chromium/ui/gfx/mac/io_surface.cc
@@ -11,8 +11,8 @@
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/mach_logging.h"
-#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/icc_profile.h"
@@ -45,7 +45,7 @@ int32_t BytesPerElement(gfx::BufferFormat format, int plane) {
return 8;
case gfx::BufferFormat::YUV_420_BIPLANAR:
static int32_t bytes_per_element[] = {1, 2};
- DCHECK_LT(static_cast<size_t>(plane), arraysize(bytes_per_element));
+ DCHECK_LT(static_cast<size_t>(plane), base::size(bytes_per_element));
return bytes_per_element[plane];
case gfx::BufferFormat::R_16:
case gfx::BufferFormat::RG_88:
diff --git a/chromium/ui/gfx/mojo/BUILD.gn b/chromium/ui/gfx/mojo/BUILD.gn
index 5a839155076..7c113cab04b 100644
--- a/chromium/ui/gfx/mojo/BUILD.gn
+++ b/chromium/ui/gfx/mojo/BUILD.gn
@@ -14,6 +14,7 @@ mojom("mojo") {
"gpu_fence_handle.mojom",
"overlay_transform.mojom",
"presentation_feedback.mojom",
+ "rrect_f.mojom",
"selection_bound.mojom",
"swap_result.mojom",
"transform.mojom",
diff --git a/chromium/ui/gfx/mojo/rrect_f.mojom b/chromium/ui/gfx/mojo/rrect_f.mojom
new file mode 100644
index 00000000000..fc9337a07ac
--- /dev/null
+++ b/chromium/ui/gfx/mojo/rrect_f.mojom
@@ -0,0 +1,26 @@
+// 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 gfx.mojom;
+
+import "ui/gfx/geometry/mojo/geometry.mojom";
+
+enum RRectFType {
+ kEmpty,
+ kRect,
+ kSingle,
+ kSimple,
+ kOval,
+ kComplex,
+};
+
+// See ui/gfx/rrect_f.h.
+struct RRectF {
+ RRectFType type;
+ gfx.mojom.RectF rect;
+ gfx.mojom.Vector2dF upper_left;
+ gfx.mojom.Vector2dF upper_right;
+ gfx.mojom.Vector2dF lower_right;
+ gfx.mojom.Vector2dF lower_left;
+};
diff --git a/chromium/ui/gfx/mojo/rrect_f.typemap b/chromium/ui/gfx/mojo/rrect_f.typemap
new file mode 100644
index 00000000000..b99cb4a3c39
--- /dev/null
+++ b/chromium/ui/gfx/mojo/rrect_f.typemap
@@ -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.
+
+mojom = "//ui/gfx/mojo/rrect_f.mojom"
+public_headers = [ "//ui/gfx/rrect_f.h" ]
+traits_headers = [ "//ui/gfx/mojo/rrect_f_struct_traits.h" ]
+type_mappings = [ "gfx.mojom.RRectF=gfx::RRectF" ]
+deps = [
+ "//ui/gfx/geometry/mojo:struct_traits",
+]
diff --git a/chromium/ui/gfx/mojo/rrect_f_struct_traits.h b/chromium/ui/gfx/mojo/rrect_f_struct_traits.h
new file mode 100644
index 00000000000..46f97d2548b
--- /dev/null
+++ b/chromium/ui/gfx/mojo/rrect_f_struct_traits.h
@@ -0,0 +1,112 @@
+// 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_MOJO_RRECT_F_STRUCT_TRAITS_H_
+#define UI_GFX_MOJO_RRECT_F_STRUCT_TRAITS_H_
+
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+#include "ui/gfx/mojo/rrect_f.mojom-shared.h"
+#include "ui/gfx/rrect_f.h"
+
+namespace mojo {
+
+namespace {
+
+gfx::mojom::RRectFType GfxRRectFTypeToMojo(gfx::RRectF::Type type) {
+ switch (type) {
+ case gfx::RRectF::Type::kEmpty:
+ return gfx::mojom::RRectFType::kEmpty;
+ case gfx::RRectF::Type::kRect:
+ return gfx::mojom::RRectFType::kRect;
+ case gfx::RRectF::Type::kSingle:
+ return gfx::mojom::RRectFType::kSingle;
+ case gfx::RRectF::Type::kSimple:
+ return gfx::mojom::RRectFType::kSimple;
+ case gfx::RRectF::Type::kOval:
+ return gfx::mojom::RRectFType::kOval;
+ case gfx::RRectF::Type::kComplex:
+ return gfx::mojom::RRectFType::kComplex;
+ }
+ NOTREACHED();
+ return gfx::mojom::RRectFType::kEmpty;
+}
+
+gfx::RRectF::Type MojoRRectFTypeToGfx(gfx::mojom::RRectFType type) {
+ switch (type) {
+ case gfx::mojom::RRectFType::kEmpty:
+ return gfx::RRectF::Type::kEmpty;
+ case gfx::mojom::RRectFType::kRect:
+ return gfx::RRectF::Type::kRect;
+ case gfx::mojom::RRectFType::kSingle:
+ return gfx::RRectF::Type::kSingle;
+ case gfx::mojom::RRectFType::kSimple:
+ return gfx::RRectF::Type::kSimple;
+ case gfx::mojom::RRectFType::kOval:
+ return gfx::RRectF::Type::kOval;
+ case gfx::mojom::RRectFType::kComplex:
+ return gfx::RRectF::Type::kComplex;
+ }
+ NOTREACHED();
+ return gfx::RRectF::Type::kEmpty;
+}
+
+} // namespace
+
+template <>
+struct StructTraits<gfx::mojom::RRectFDataView, gfx::RRectF> {
+ static gfx::mojom::RRectFType type(const gfx::RRectF& input) {
+ return GfxRRectFTypeToMojo(input.GetType());
+ }
+
+ static gfx::RectF rect(const gfx::RRectF& input) { return input.rect(); }
+
+ static gfx::Vector2dF upper_left(const gfx::RRectF& input) {
+ return input.GetCornerRadii(gfx::RRectF::Corner::kUpperLeft);
+ }
+
+ static gfx::Vector2dF upper_right(const gfx::RRectF& input) {
+ return input.GetCornerRadii(gfx::RRectF::Corner::kUpperRight);
+ }
+
+ static gfx::Vector2dF lower_right(const gfx::RRectF& input) {
+ return input.GetCornerRadii(gfx::RRectF::Corner::kLowerRight);
+ }
+
+ static gfx::Vector2dF lower_left(const gfx::RRectF& input) {
+ return input.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft);
+ }
+
+ static bool Read(gfx::mojom::RRectFDataView data, gfx::RRectF* out) {
+ gfx::RRectF::Type type(MojoRRectFTypeToGfx(data.type()));
+ gfx::RectF rect;
+ if (!data.ReadRect(&rect))
+ return false;
+ if (type <= gfx::RRectF::Type::kRect) {
+ *out = gfx::RRectF(rect);
+ return true;
+ }
+ gfx::Vector2dF upper_left;
+ if (!data.ReadUpperLeft(&upper_left))
+ return false;
+ *out = gfx::RRectF(rect, upper_left.x(), upper_left.y());
+ if (type <= gfx::RRectF::Type::kSimple)
+ return true;
+ gfx::Vector2dF upper_right;
+ gfx::Vector2dF lower_right;
+ gfx::Vector2dF lower_left;
+ if (!data.ReadUpperRight(&upper_right) ||
+ !data.ReadLowerRight(&lower_right) ||
+ !data.ReadLowerLeft(&lower_left)) {
+ return false;
+ }
+ out->SetCornerRadii(gfx::RRectF::Corner::kUpperRight, upper_right);
+ out->SetCornerRadii(gfx::RRectF::Corner::kLowerRight, lower_right);
+ out->SetCornerRadii(gfx::RRectF::Corner::kLowerLeft, lower_left);
+ return true;
+ }
+};
+
+} // namespace mojo
+
+#endif // UI_GFX_MOJO_RRECT_F_STRUCT_TRAITS_H_
diff --git a/chromium/ui/gfx/mojo/struct_traits_unittest.cc b/chromium/ui/gfx/mojo/struct_traits_unittest.cc
index b726fa2eb3a..c63b477725e 100644
--- a/chromium/ui/gfx/mojo/struct_traits_unittest.cc
+++ b/chromium/ui/gfx/mojo/struct_traits_unittest.cc
@@ -15,6 +15,7 @@
#include "ui/gfx/mojo/presentation_feedback_struct_traits.h"
#include "ui/gfx/mojo/traits_test_service.mojom.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/rrect_f.h"
#include "ui/gfx/selection_bound.h"
#include "ui/gfx/transform.h"
@@ -59,6 +60,10 @@ class StructTraitsTest : public testing::Test, public mojom::TraitsTestService {
std::move(callback).Run(std::move(handle));
}
+ void EchoRRectF(const RRectF& r, EchoRRectFCallback callback) override {
+ std::move(callback).Run(r);
+ }
+
base::MessageLoop loop_;
mojo::BindingSet<TraitsTestService> traits_test_bindings_;
@@ -229,4 +234,36 @@ TEST_F(StructTraitsTest, PresentationFeedback) {
EXPECT_EQ(flags, output.flags);
}
+TEST_F(StructTraitsTest, RRectF) {
+ gfx::RRectF input(40, 50, 60, 70, 1, 2);
+ input.SetCornerRadii(RRectF::Corner::kUpperRight, 3, 4);
+ input.SetCornerRadii(RRectF::Corner::kLowerRight, 5, 6);
+ input.SetCornerRadii(RRectF::Corner::kLowerLeft, 7, 8);
+ EXPECT_EQ(input.GetType(), RRectF::Type::kComplex);
+ mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
+ gfx::RRectF output;
+ proxy->EchoRRectF(input, &output);
+ EXPECT_EQ(input, output);
+ input = gfx::RRectF(40, 50, 0, 70, 0);
+ EXPECT_EQ(input.GetType(), RRectF::Type::kEmpty);
+ proxy->EchoRRectF(input, &output);
+ EXPECT_EQ(input, output);
+ input = RRectF(40, 50, 60, 70, 0);
+ EXPECT_EQ(input.GetType(), RRectF::Type::kRect);
+ proxy->EchoRRectF(input, &output);
+ EXPECT_EQ(input, output);
+ input = RRectF(40, 50, 60, 70, 5);
+ EXPECT_EQ(input.GetType(), RRectF::Type::kSingle);
+ proxy->EchoRRectF(input, &output);
+ EXPECT_EQ(input, output);
+ input = RRectF(40, 50, 60, 70, 6, 3);
+ EXPECT_EQ(input.GetType(), RRectF::Type::kSimple);
+ proxy->EchoRRectF(input, &output);
+ EXPECT_EQ(input, output);
+ input = RRectF(40, 50, 60, 70, 30, 35);
+ EXPECT_EQ(input.GetType(), RRectF::Type::kOval);
+ proxy->EchoRRectF(input, &output);
+ EXPECT_EQ(input, output);
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/mojo/traits_test_service.mojom b/chromium/ui/gfx/mojo/traits_test_service.mojom
index 6a1cf64d8ea..ad863f17aa6 100644
--- a/chromium/ui/gfx/mojo/traits_test_service.mojom
+++ b/chromium/ui/gfx/mojo/traits_test_service.mojom
@@ -6,6 +6,7 @@ module gfx.mojom;
import "ui/gfx/mojo/accelerated_widget.mojom";
import "ui/gfx/mojo/buffer_types.mojom";
+import "ui/gfx/mojo/rrect_f.mojom";
import "ui/gfx/mojo/selection_bound.mojom";
import "ui/gfx/mojo/transform.mojom";
@@ -21,4 +22,7 @@ interface TraitsTestService {
[Sync]
EchoGpuMemoryBufferHandle(GpuMemoryBufferHandle g)
=> (GpuMemoryBufferHandle pass);
+
+ [Sync]
+ EchoRRectF(RRectF t) => (RRectF pass);
};
diff --git a/chromium/ui/gfx/native_widget_types.h b/chromium/ui/gfx/native_widget_types.h
index 2b0b362c662..121562aaa67 100644
--- a/chromium/ui/gfx/native_widget_types.h
+++ b/chromium/ui/gfx/native_widget_types.h
@@ -207,7 +207,9 @@ typedef id NativeViewAccessible;
#if defined(USE_X11)
typedef AtkObject* NativeViewAccessible;
#else
-typedef void* NativeViewAccessible;
+typedef struct _UnimplementedNativeViewAccessible
+ UnimplementedNativeViewAccessible;
+typedef UnimplementedNativeViewAccessible* NativeViewAccessible;
#endif
#endif
diff --git a/chromium/ui/gfx/nine_image_painter.cc b/chromium/ui/gfx/nine_image_painter.cc
index fa1afe44b03..1d2ae8ed537 100644
--- a/chromium/ui/gfx/nine_image_painter.cc
+++ b/chromium/ui/gfx/nine_image_painter.cc
@@ -8,7 +8,7 @@
#include <limits>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkScalar.h"
@@ -52,8 +52,8 @@ void Fill(Canvas* c,
} // namespace
NineImagePainter::NineImagePainter(const std::vector<ImageSkia>& images) {
- DCHECK_EQ(arraysize(images_), images.size());
- for (size_t i = 0; i < arraysize(images_); ++i)
+ DCHECK_EQ(base::size(images_), images.size());
+ for (size_t i = 0; i < base::size(images_); ++i)
images_[i] = images[i];
}
@@ -112,8 +112,8 @@ void NineImagePainter::Paint(Canvas* canvas,
canvas->Translate(gfx::Vector2d(left_in_pixels, top_in_pixels));
ImageSkiaRep image_reps[9];
- static_assert(arraysize(image_reps) == arraysize(images_), "");
- for (size_t i = 0; i < arraysize(image_reps); ++i) {
+ static_assert(base::size(image_reps) == std::extent<decltype(images_)>(), "");
+ for (size_t i = 0; i < base::size(image_reps); ++i) {
image_reps[i] = images_[i].GetRepresentation(scale);
DCHECK(image_reps[i].is_null() || image_reps[i].scale() == scale);
}
diff --git a/chromium/ui/gfx/paint_throbber.cc b/chromium/ui/gfx/paint_throbber.cc
index 17b2f13a9a2..83a31693365 100644
--- a/chromium/ui/gfx/paint_throbber.cc
+++ b/chromium/ui/gfx/paint_throbber.cc
@@ -31,17 +31,20 @@ void PaintArc(Canvas* canvas,
const Rect& bounds,
SkColor color,
SkScalar start_angle,
- SkScalar sweep) {
- // Stroke width depends on size.
- // . For size < 28: 3 - (28 - size) / 16
- // . For 28 <= size: (8 + size) / 12
- SkScalar stroke_width = bounds.width() < 28
- ? 3.0 - SkIntToScalar(28 - bounds.width()) / 16.0
- : SkIntToScalar(bounds.width() + 8) / 12.0;
+ SkScalar sweep,
+ base::Optional<SkScalar> stroke_width) {
+ if (!stroke_width) {
+ // Stroke width depends on size.
+ // . For size < 28: 3 - (28 - size) / 16
+ // . For 28 <= size: (8 + size) / 12
+ stroke_width = bounds.width() < 28
+ ? 3.0 - SkIntToScalar(28 - bounds.width()) / 16.0
+ : SkIntToScalar(bounds.width() + 8) / 12.0;
+ }
Rect oval = bounds;
// Inset by half the stroke width to make sure the whole arc is inside
// the visible rect.
- int inset = SkScalarCeilToInt(stroke_width / 2.0);
+ int inset = SkScalarCeilToInt(*stroke_width / 2.0);
oval.Inset(inset, inset);
SkPath path;
@@ -50,7 +53,7 @@ void PaintArc(Canvas* canvas,
cc::PaintFlags flags;
flags.setColor(color);
flags.setStrokeCap(cc::PaintFlags::kRound_Cap);
- flags.setStrokeWidth(stroke_width);
+ flags.setStrokeWidth(*stroke_width);
flags.setStyle(cc::PaintFlags::kStroke_Style);
flags.setAntiAlias(true);
canvas->DrawPath(path, flags);
@@ -78,11 +81,13 @@ void CalculateWaitingAngles(const base::TimeDelta& elapsed_time,
// This is a Skia port of the MD spinner SVG. The |start_angle| rotation
// here corresponds to the 'rotate' animation.
-void PaintThrobberSpinningWithStartAngle(Canvas* canvas,
- const Rect& bounds,
- SkColor color,
- const base::TimeDelta& elapsed_time,
- int64_t start_angle) {
+void PaintThrobberSpinningWithStartAngle(
+ Canvas* canvas,
+ const Rect& bounds,
+ SkColor color,
+ const base::TimeDelta& elapsed_time,
+ int64_t start_angle,
+ base::Optional<SkScalar> stroke_width) {
// The sweep angle ranges from -270 to 270 over 1333ms. CSS
// animation timing functions apply in between key frames, so we have to
// break up the 1333ms into two keyframes (-270 to 0, then 0 to 270).
@@ -112,7 +117,7 @@ void PaintThrobberSpinningWithStartAngle(Canvas* canvas,
// |arc_time| period has elapsed. See SVG's 'rot' animation.
int64_t rot_keyframe = (elapsed_time / (arc_time * 2)) % 4;
PaintArc(canvas, bounds, color, start_angle + rot_keyframe * kMaxArcSize,
- sweep);
+ sweep, stroke_width);
}
} // namespace
@@ -120,26 +125,31 @@ void PaintThrobberSpinningWithStartAngle(Canvas* canvas,
void PaintThrobberSpinning(Canvas* canvas,
const Rect& bounds,
SkColor color,
- const base::TimeDelta& elapsed_time) {
+ const base::TimeDelta& elapsed_time,
+ base::Optional<SkScalar> stroke_width) {
base::TimeDelta rotation_time =
base::TimeDelta::FromMilliseconds(kRotationTimeMs);
int64_t start_angle = 270 + 360 * elapsed_time / rotation_time;
PaintThrobberSpinningWithStartAngle(canvas, bounds, color, elapsed_time,
- start_angle);
+ start_angle, stroke_width);
}
void PaintThrobberWaiting(Canvas* canvas,
- const Rect& bounds, SkColor color, const base::TimeDelta& elapsed_time) {
+ const Rect& bounds,
+ SkColor color,
+ const base::TimeDelta& elapsed_time,
+ base::Optional<SkScalar> stroke_width) {
int64_t start_angle = 0, sweep = 0;
CalculateWaitingAngles(elapsed_time, &start_angle, &sweep);
- PaintArc(canvas, bounds, color, start_angle, sweep);
+ PaintArc(canvas, bounds, color, start_angle, sweep, stroke_width);
}
void PaintThrobberSpinningAfterWaiting(Canvas* canvas,
const Rect& bounds,
SkColor color,
const base::TimeDelta& elapsed_time,
- ThrobberWaitingState* waiting_state) {
+ ThrobberWaitingState* waiting_state,
+ base::Optional<SkScalar> stroke_width) {
int64_t waiting_start_angle = 0, waiting_sweep = 0;
CalculateWaitingAngles(waiting_state->elapsed_time, &waiting_start_angle,
&waiting_sweep);
@@ -162,15 +172,15 @@ void PaintThrobberSpinningAfterWaiting(Canvas* canvas,
// Blend the color between "waiting" and "spinning" states.
base::TimeDelta color_fade_time = base::TimeDelta::FromMilliseconds(900);
- double color_progress = 1.0;
+ float color_progress = 1.0f;
if (elapsed_time < color_fade_time) {
- color_progress = Tween::CalculateValue(
+ color_progress = static_cast<float>(Tween::CalculateValue(
Tween::LINEAR_OUT_SLOW_IN,
static_cast<double>(elapsed_time.InMicroseconds()) /
- color_fade_time.InMicroseconds());
+ color_fade_time.InMicroseconds()));
}
- SkColor blend_color = color_utils::AlphaBlend(color, waiting_state->color,
- color_progress * 255);
+ SkColor blend_color =
+ color_utils::AlphaBlend(color, waiting_state->color, color_progress);
int64_t start_angle =
waiting_start_angle +
@@ -179,7 +189,8 @@ void PaintThrobberSpinningAfterWaiting(Canvas* canvas,
elapsed_time + waiting_state->arc_time_offset;
PaintThrobberSpinningWithStartAngle(canvas, bounds, blend_color,
- effective_elapsed_time, start_angle);
+ effective_elapsed_time, start_angle,
+ stroke_width);
}
GFX_EXPORT void PaintNewThrobberWaiting(Canvas* canvas,
@@ -223,11 +234,9 @@ GFX_EXPORT void PaintNewThrobberWaiting(Canvas* canvas,
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);
+ canvas->DrawRoundRect(bounds, bounds.height() / 2, flags);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/paint_throbber.h b/chromium/ui/gfx/paint_throbber.h
index a373d20a176..a6603757b5b 100644
--- a/chromium/ui/gfx/paint_throbber.h
+++ b/chromium/ui/gfx/paint_throbber.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include "base/optional.h"
#include "base/time/time.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/gfx_export.h"
@@ -33,13 +34,21 @@ struct GFX_EXPORT ThrobberWaitingState {
};
// Paints a single frame of the throbber in the "spinning", aka Material, state.
-GFX_EXPORT void PaintThrobberSpinning(Canvas* canvas,
- const Rect& bounds, SkColor color, const base::TimeDelta& elapsed_time);
+GFX_EXPORT void PaintThrobberSpinning(
+ Canvas* canvas,
+ const Rect& bounds,
+ SkColor color,
+ const base::TimeDelta& elapsed_time,
+ base::Optional<SkScalar> stroke_width = base::nullopt);
// Paints a throbber in the "waiting" state. Used when waiting on a network
// response, for example.
-GFX_EXPORT void PaintThrobberWaiting(Canvas* canvas,
- const Rect& bounds, SkColor color, const base::TimeDelta& elapsed_time);
+GFX_EXPORT void PaintThrobberWaiting(
+ Canvas* canvas,
+ const Rect& bounds,
+ SkColor color,
+ const base::TimeDelta& elapsed_time,
+ base::Optional<SkScalar> stroke_width = base::nullopt);
// Paint a throbber in the "spinning" state, smoothly transitioning from a
// previous "waiting" state described by |waiting_state|, which is an in-out
@@ -49,7 +58,8 @@ GFX_EXPORT void PaintThrobberSpinningAfterWaiting(
const Rect& bounds,
SkColor color,
const base::TimeDelta& elapsed_time,
- ThrobberWaitingState* waiting_state);
+ ThrobberWaitingState* waiting_state,
+ base::Optional<SkScalar> stroke_width = base::nullopt);
// Paints a throbber in the "waiting" state (bouncing back and forth). Used when
// waiting on a network response, for example.
diff --git a/chromium/ui/gfx/paint_vector_icon.cc b/chromium/ui/gfx/paint_vector_icon.cc
index ea4dc6a1cea..d6b4b832e5e 100644
--- a/chromium/ui/gfx/paint_vector_icon.cc
+++ b/chromium/ui/gfx/paint_vector_icon.cc
@@ -51,7 +51,7 @@ const VectorIconRep* GetRepForPxSize(const VectorIcon& icon, int icon_size_px) {
// Since |VectorIcon::reps| is sorted in descending order by size, search in
// reverse order for an icon that is equal to or greater than |icon_size_px|.
- for (int i = icon.reps_size - 1; i >= 0; --i) {
+ for (int i = static_cast<int>(icon.reps_size - 1); i >= 0; --i) {
if (GetCanvasDimensions(icon.reps[i].path) >= icon_size_px)
return &icon.reps[i];
}
@@ -210,9 +210,6 @@ void PaintPath(Canvas* canvas,
int dip_size,
SkColor color,
const base::TimeDelta& elapsed_time) {
- SkPath path;
- path.setFillType(SkPath::kEvenOdd_FillType);
-
int canvas_size = kReferenceSizeDip;
std::vector<SkPath> paths;
std::vector<cc::PaintFlags> flags_array;
diff --git a/chromium/ui/gfx/paint_vector_icon_unittest.cc b/chromium/ui/gfx/paint_vector_icon_unittest.cc
index b472dff7b0f..ca8efecbcef 100644
--- a/chromium/ui/gfx/paint_vector_icon_unittest.cc
+++ b/chromium/ui/gfx/paint_vector_icon_unittest.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "base/i18n/rtl.h"
+#include "base/stl_util.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/paint_recorder.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -50,7 +51,7 @@ TEST(VectorIconTest, RelativeMoveToAfterClose) {
MOVE_TO, 4, 5, LINE_TO, 10, 11, CLOSE,
// This move should use (4, 5) as the start point rather than (10, 11).
R_MOVE_TO, 20, 21, R_LINE_TO, 50, 51};
- const VectorIconRep rep_list[] = {{elements, arraysize(elements)}};
+ const VectorIconRep rep_list[] = {{elements, base::size(elements)}};
const VectorIcon icon = {rep_list, 1u};
PaintVectorIcon(&canvas, icon, 100, SK_ColorMAGENTA);
@@ -91,7 +92,7 @@ TEST(VectorIconTest, FlipsInRtl) {
R_H_LINE_TO,
-20,
CLOSE};
- const VectorIconRep rep_list[] = {{elements, arraysize(elements)}};
+ const VectorIconRep rep_list[] = {{elements, base::size(elements)}};
const VectorIcon icon = {rep_list, 1u};
PaintVectorIcon(&canvas, icon, canvas_size, color);
@@ -217,11 +218,11 @@ TEST(VectorIconTest, CorrectSizePainted) {
0,
CLOSE};
// VectorIconReps are always sorted in descending order of size.
- const VectorIconRep rep_list[] = {{elements48, arraysize(elements48)},
- {elements32, arraysize(elements32)},
- {elements24, arraysize(elements24)},
- {elements20, arraysize(elements20)},
- {elements16, arraysize(elements16)}};
+ const VectorIconRep rep_list[] = {{elements48, base::size(elements48)},
+ {elements32, base::size(elements32)},
+ {elements24, base::size(elements24)},
+ {elements20, base::size(elements20)},
+ {elements16, base::size(elements16)}};
const VectorIcon icon = {rep_list, 5u};
// Test exact sizes paint the correctly sized icon, including the largest and
diff --git a/chromium/ui/gfx/path.cc b/chromium/ui/gfx/path.cc
deleted file mode 100644
index 16d73946daa..00000000000
--- a/chromium/ui/gfx/path.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/path.h"
-
-namespace gfx {
-
-Path::Path()
- : SkPath() {
-}
-
-Path::~Path() {
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/path.h b/chromium/ui/gfx/path.h
deleted file mode 100644
index 259053a48b3..00000000000
--- a/chromium/ui/gfx/path.h
+++ /dev/null
@@ -1,27 +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_GFX_PATH_H_
-#define UI_GFX_PATH_H_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace gfx {
-
-// DEPRECATED, use SkPath directly.
-// TODO(collinbaker): remove this class and replace all references with SkPath.
-class GFX_EXPORT Path : public SkPath {
- public:
- Path();
- ~Path();
-};
-
-}
-
-#endif // UI_GFX_PATH_H_
diff --git a/chromium/ui/gfx/path_mac.mm b/chromium/ui/gfx/path_mac.mm
index 109f80741f4..3cf70eeeea8 100644
--- a/chromium/ui/gfx/path_mac.mm
+++ b/chromium/ui/gfx/path_mac.mm
@@ -6,8 +6,9 @@
#import <Cocoa/Cocoa.h>
+#include "base/stl_util.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/path.h"
namespace {
@@ -38,7 +39,7 @@ NSBezierPath* CreateNSBezierPathFromSkPath(const SkPath& path) {
SkPath::Verb verb;
NSPoint points[4];
while ((verb = iter.next(sk_points)) != SkPath::kDone_Verb) {
- for (size_t i = 0; i < arraysize(points); i++)
+ for (size_t i = 0; i < base::size(points); i++)
points[i] = NSMakePoint(sk_points[i].x(), sk_points[i].y());
switch (verb) {
diff --git a/chromium/ui/gfx/path_mac_unittest.mm b/chromium/ui/gfx/path_mac_unittest.mm
index d1d4a99234e..522e7ce5045 100644
--- a/chromium/ui/gfx/path_mac_unittest.mm
+++ b/chromium/ui/gfx/path_mac_unittest.mm
@@ -9,11 +9,12 @@
#import <Cocoa/Cocoa.h>
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/path.h"
namespace gfx {
@@ -117,7 +118,7 @@ TEST(CreateNSBezierPathFromSkPathTest, TwoRectanglesPath) {
const NSPoint outside_points[] = {{-1, -1}, {-1, 51}, {51, 51}, {51, -1},
{99, 99}, {99, 151}, {151, 151}, {151, 99},
{75, 75}, {-5, -5}};
- ASSERT_EQ(arraysize(inside_points), arraysize(outside_points));
+ ASSERT_EQ(base::size(inside_points), base::size(outside_points));
const Rect expected_bounds(0, 0, 150, 150);
SkPath path;
@@ -127,7 +128,7 @@ TEST(CreateNSBezierPathFromSkPathTest, TwoRectanglesPath) {
// Check points near the boundary of the path and verify that they are
// reported correctly as being inside/outside the path.
- for (size_t i = 0; i < arraysize(inside_points); i++) {
+ for (size_t i = 0; i < base::size(inside_points); i++) {
EXPECT_TRUE([result containsPoint:inside_points[i]]);
EXPECT_FALSE([result containsPoint:outside_points[i]]);
}
@@ -227,7 +228,7 @@ TEST(CreateNSBezierPathFromSkPathTest, RoundedRectanglePath) {
{kRectangleWidth / 2.0, kRectangleHeight + kCushion},
// Left middle.
{-kCushion, kRectangleHeight / 2.0}};
- ASSERT_EQ(arraysize(inside_points), arraysize(outside_points));
+ ASSERT_EQ(base::size(inside_points), base::size(outside_points));
SkPath path;
path.addRRect(rrect);
@@ -235,7 +236,7 @@ TEST(CreateNSBezierPathFromSkPathTest, RoundedRectanglePath) {
// Check points near the boundary of the path and verify that they are
// reported correctly as being inside/outside the path.
- for (size_t i = 0; i < arraysize(inside_points); i++) {
+ for (size_t i = 0; i < base::size(inside_points); i++) {
EXPECT_TRUE([result containsPoint:inside_points[i]]);
EXPECT_FALSE([result containsPoint:outside_points[i]]);
}
diff --git a/chromium/ui/gfx/path_win.cc b/chromium/ui/gfx/path_win.cc
index e217447309a..3a73d9171f2 100644
--- a/chromium/ui/gfx/path_win.cc
+++ b/chromium/ui/gfx/path_win.cc
@@ -7,8 +7,8 @@
#include <memory>
#include "base/win/scoped_gdi_object.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/path.h"
namespace gfx {
diff --git a/chromium/ui/gfx/path_win_unittest.cc b/chromium/ui/gfx/path_win_unittest.cc
index ca9e13a2bca..dc7982392c4 100644
--- a/chromium/ui/gfx/path_win_unittest.cc
+++ b/chromium/ui/gfx/path_win_unittest.cc
@@ -9,12 +9,12 @@
#include <algorithm>
#include <vector>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/win/scoped_gdi_object.h"
#include "skia/ext/skia_utils_win.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRRect.h"
-#include "ui/gfx/path.h"
namespace gfx {
@@ -77,14 +77,14 @@ TEST(CreateHRGNFromSkPathTest, RoundCornerTest) {
{ 16, 49, 34, 50 },
};
- Path path;
+ SkPath path;
SkRRect rrect;
rrect.setRectXY(SkRect::MakeWH(50, 50), 20, 20);
path.addRRect(rrect);
base::win::ScopedRegion region(CreateHRGNFromSkPath(path));
const std::vector<SkIRect>& region_rects = GetRectsFromHRGN(region.get());
- EXPECT_EQ(arraysize(rects), region_rects.size());
- for (size_t i = 0; i < arraysize(rects) && i < region_rects.size(); ++i)
+ EXPECT_EQ(base::size(rects), region_rects.size());
+ for (size_t i = 0; i < base::size(rects) && i < region_rects.size(); ++i)
EXPECT_EQ(rects[i], region_rects[i]);
}
@@ -96,20 +96,20 @@ TEST(CreateHRGNFromSkPathTest, NonContiguousPath) {
{ 100, 100, 150, 150},
};
- Path path;
+ SkPath path;
for (const SkIRect& rect : rects) {
path.addRect(SkRect::Make(rect));
}
base::win::ScopedRegion region(CreateHRGNFromSkPath(path));
const std::vector<SkIRect>& region_rects = GetRectsFromHRGN(region.get());
- ASSERT_EQ(arraysize(rects), region_rects.size());
- for (size_t i = 0; i < arraysize(rects); ++i)
+ ASSERT_EQ(base::size(rects), region_rects.size());
+ for (size_t i = 0; i < base::size(rects); ++i)
EXPECT_EQ(rects[i], region_rects[i]);
}
// Check that empty region is returned for empty path.
TEST(CreateHRGNFromSkPathTest, EmptyPath) {
- Path path;
+ SkPath path;
base::win::ScopedRegion empty_region(::CreateRectRgn(0, 0, 0, 0));
base::win::ScopedRegion region(CreateHRGNFromSkPath(path));
EXPECT_TRUE(::EqualRgn(empty_region.get(), region.get()));
diff --git a/chromium/ui/gfx/path_x11.cc b/chromium/ui/gfx/path_x11.cc
index 09d0a0b645a..8ab444e0bbb 100644
--- a/chromium/ui/gfx/path_x11.cc
+++ b/chromium/ui/gfx/path_x11.cc
@@ -6,8 +6,8 @@
#include <memory>
+#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/x/x11.h"
namespace gfx {
diff --git a/chromium/ui/gfx/platform_font_mac_unittest.mm b/chromium/ui/gfx/platform_font_mac_unittest.mm
index f031568399d..422e2425548 100644
--- a/chromium/ui/gfx/platform_font_mac_unittest.mm
+++ b/chromium/ui/gfx/platform_font_mac_unittest.mm
@@ -8,7 +8,7 @@
#include <stddef.h>
#include "base/mac/mac_util.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h"
@@ -286,7 +286,7 @@ TEST(PlatformFontMacTest, ValidateFontHeight) {
gfx::Font::FontStyle styles[] = {gfx::Font::NORMAL, gfx::Font::ITALIC,
gfx::Font::UNDERLINE};
- for (size_t i = 0; i < arraysize(styles); ++i) {
+ for (size_t i = 0; i < base::size(styles); ++i) {
SCOPED_TRACE(testing::Message() << "Font::FontStyle: " << styles[i]);
// Include the range of sizes used by ResourceBundle::FontStyle (-1 to +8).
for (int delta = -1; delta <= 8; ++delta) {
diff --git a/chromium/ui/gfx/platform_font_skia.cc b/chromium/ui/gfx/platform_font_skia.cc
index 81a77adcee7..b8910fe253d 100644
--- a/chromium/ui/gfx/platform_font_skia.cc
+++ b/chromium/ui/gfx/platform_font_skia.cc
@@ -13,8 +13,8 @@
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkFontStyle.h"
-#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkString.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
@@ -306,18 +306,14 @@ void PlatformFontSkia::ComputeMetricsIfNecessary() {
if (metrics_need_computation_) {
metrics_need_computation_ = false;
- SkPaint paint;
- paint.setAntiAlias(false);
- paint.setSubpixelText(false);
- paint.setTextSize(font_size_pixels_);
- paint.setTypeface(typeface_);
- paint.setFakeBoldText(weight_ >= Font::Weight::BOLD &&
- !typeface_->isBold());
- paint.setTextSkewX((Font::ITALIC & style_) && !typeface_->isItalic()
- ? -SK_Scalar1 / 4
- : 0);
+ SkFont font(typeface_, font_size_pixels_);
+ font.setEdging(SkFont::Edging::kAlias);
+ font.setEmbolden(weight_ >= Font::Weight::BOLD && !typeface_->isBold());
+ font.setSkewX((Font::ITALIC & style_) && !typeface_->isItalic()
+ ? -SK_Scalar1 / 4
+ : 0);
SkFontMetrics metrics;
- paint.getFontMetrics(&metrics);
+ font.getMetrics(&metrics);
ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
diff --git a/chromium/ui/gfx/platform_font_win.cc b/chromium/ui/gfx/platform_font_win.cc
index e7c628c75aa..a904ec3a219 100644
--- a/chromium/ui/gfx/platform_font_win.cc
+++ b/chromium/ui/gfx/platform_font_win.cc
@@ -18,8 +18,8 @@
#include "base/containers/flat_map.h"
#include "base/debug/alias.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/no_destructor.h"
+#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
@@ -92,7 +92,7 @@ HRESULT FindDirectWriteFontForLOGFONT(IDWriteFactory* factory,
if (SUCCEEDED(hr)) {
hr = font_collection->GetFontFromFontFace(font_face.Get(), dwrite_font);
if (SUCCEEDED(hr)) {
- wcscpy_s(font_info->lfFaceName, arraysize(font_info->lfFaceName),
+ wcscpy_s(font_info->lfFaceName, base::size(font_info->lfFaceName),
converted_font.lfFaceName);
}
}
@@ -155,12 +155,12 @@ HRESULT GetMatchingDirectWriteFont(LOGFONT* font_info,
}
if (wcsncmp(font_info->lfFaceName, metrics.lfMessageFont.lfFaceName,
- arraysize(font_info->lfFaceName))) {
+ base::size(font_info->lfFaceName))) {
// First try the GDI compat route to get a matching DirectWrite font. If
// that succeeds we are good. If not find a matching font from the font
// collection.
- wcscpy_s(font_info->lfFaceName, arraysize(font_info->lfFaceName),
- metrics.lfMessageFont.lfFaceName);
+ wcscpy_s(font_info->lfFaceName, base::size(font_info->lfFaceName),
+ metrics.lfMessageFont.lfFaceName);
hr = FindDirectWriteFontForLOGFONT(factory, font_info, dwrite_font);
if (SUCCEEDED(hr))
return hr;
@@ -219,7 +219,7 @@ HRESULT GetMatchingDirectWriteFont(LOGFONT* font_info,
base::string16 font_name;
gfx::GetFamilyNameFromDirectWriteFont(*dwrite_font, &font_name);
- wcscpy_s(font_info->lfFaceName, arraysize(font_info->lfFaceName),
+ wcscpy_s(font_info->lfFaceName, base::size(font_info->lfFaceName),
font_name.c_str());
return hr;
}
@@ -377,7 +377,7 @@ HRESULT GetFamilyNameFromDirectWriteFont(IDWriteFont* dwrite_font,
// Add support for retrieving the family for the current locale.
wchar_t family_name_for_locale[MAX_PATH] = {0};
hr = family_names->GetString(0, family_name_for_locale,
- arraysize(family_name_for_locale));
+ base::size(family_name_for_locale));
if (FAILED(hr))
CHECK(false);
@@ -513,7 +513,7 @@ std::string PlatformFontWin::GetLocalizedFontName() const {
// locale, GetTextFace() returns the localized name.
base::win::ScopedSelectObject font(memory_dc.Get(), font_ref_->hfont());
wchar_t localized_font_name[LF_FACESIZE];
- int length = GetTextFace(memory_dc.Get(), arraysize(localized_font_name),
+ int length = GetTextFace(memory_dc.Get(), base::size(localized_font_name),
&localized_font_name[0]);
if (length <= 0)
return GetFontName();
@@ -673,21 +673,20 @@ PlatformFontWin::HFontRef* PlatformFontWin::CreateHFontRefFromSkia(
FontRenderParams::SubpixelRenderingToSkiaLCDOrientation(
font_params.subpixel_rendering));
- SkPaint paint;
- paint.setAntiAlias(font_params.antialiasing);
- paint.setTypeface(std::move(skia_face));
- paint.setTextSize(-font_info.lfHeight);
+ SkFont font(std::move(skia_face), -font_info.lfHeight);
+ font.setEdging(font_params.antialiasing ? SkFont::Edging::kAntiAlias
+ : SkFont::Edging::kAlias);
SkFontMetrics skia_metrics;
- paint.getFontMetrics(&skia_metrics);
+ font.getMetrics(&skia_metrics);
// The calculations below are similar to those in the CreateHFontRef
// function. The height, baseline and cap height are rounded up to ensure
// that they match up closely with GDI.
const int height = std::ceil(skia_metrics.fDescent - skia_metrics.fAscent);
const int baseline = std::max<int>(1, std::ceil(-skia_metrics.fAscent));
- const int cap_height = std::ceil(paint.getTextSize() *
- static_cast<double>(dwrite_font_metrics.capHeight) /
- dwrite_font_metrics.designUnitsPerEm);
+ const int cap_height = std::ceil(
+ font.getSize() * static_cast<double>(dwrite_font_metrics.capHeight) /
+ dwrite_font_metrics.designUnitsPerEm);
// The metrics retrieved from skia don't have the average character width. In
// any case if we get the average character width from skia then use that or
diff --git a/chromium/ui/gfx/render_text.cc b/chromium/ui/gfx/render_text.cc
index 46dd6934bda..68b99d49658 100644
--- a/chromium/ui/gfx/render_text.cc
+++ b/chromium/ui/gfx/render_text.cc
@@ -143,26 +143,26 @@ sk_sp<cc::PaintShader> CreateFadeShader(const FontList& font_list,
const SkPoint points[2] = { PointToSkPoint(text_rect.origin()),
PointToSkPoint(text_rect.top_right()) };
- return cc::PaintShader::MakeLinearGradient(&points[0], &colors[0],
- &positions[0], colors.size(),
- SkShader::kClamp_TileMode);
+ return cc::PaintShader::MakeLinearGradient(
+ &points[0], &colors[0], &positions[0], static_cast<int>(colors.size()),
+ SkShader::kClamp_TileMode);
}
// Converts a FontRenderParams::Hinting value to the corresponding
-// cc::PaintFlags::Hinting value.
-cc::PaintFlags::Hinting FontRenderParamsHintingToPaintFlagsHinting(
+// SkFontHinting value.
+SkFontHinting FontRenderParamsHintingToSkFontHinting(
FontRenderParams::Hinting params_hinting) {
switch (params_hinting) {
case FontRenderParams::HINTING_NONE:
- return cc::PaintFlags::kNo_Hinting;
+ return SkFontHinting::kNone;
case FontRenderParams::HINTING_SLIGHT:
- return cc::PaintFlags::kSlight_Hinting;
+ return SkFontHinting::kSlight;
case FontRenderParams::HINTING_MEDIUM:
- return cc::PaintFlags::kNormal_Hinting;
+ return SkFontHinting::kNormal;
case FontRenderParams::HINTING_FULL:
- return cc::PaintFlags::kFull_Hinting;
+ return SkFontHinting::kFull;
}
- return cc::PaintFlags::kNo_Hinting;
+ return SkFontHinting::kNone;
}
// Make sure ranges don't break text graphemes. If a range in |break_list|
@@ -191,12 +191,11 @@ namespace internal {
SkiaTextRenderer::SkiaTextRenderer(Canvas* canvas)
: canvas_(canvas), canvas_skia_(canvas->sk_canvas()) {
DCHECK(canvas_skia_);
- flags_.setTextEncoding(cc::PaintFlags::kGlyphID_TextEncoding);
flags_.setStyle(cc::PaintFlags::kFill_Style);
- flags_.setAntiAlias(true);
- flags_.setSubpixelText(true);
- flags_.setLCDRenderText(true);
- flags_.setHinting(cc::PaintFlags::kNormal_Hinting);
+
+ font_.setEdging(SkFont::Edging::kSubpixelAntiAlias);
+ font_.setSubpixel(true);
+ font_.setHinting(SkFontHinting::kNormal);
}
SkiaTextRenderer::~SkiaTextRenderer() {
@@ -208,15 +207,15 @@ void SkiaTextRenderer::SetDrawLooper(sk_sp<SkDrawLooper> draw_looper) {
void SkiaTextRenderer::SetFontRenderParams(const FontRenderParams& params,
bool subpixel_rendering_suppressed) {
- ApplyRenderParams(params, subpixel_rendering_suppressed, &flags_);
+ ApplyRenderParams(params, subpixel_rendering_suppressed, &font_);
}
void SkiaTextRenderer::SetTypeface(sk_sp<SkTypeface> typeface) {
- flags_.setTypeface(std::move(typeface));
+ font_.setTypeface(std::move(typeface));
}
void SkiaTextRenderer::SetTextSize(SkScalar size) {
- flags_.setTextSize(size);
+ font_.setSize(size);
}
void SkiaTextRenderer::SetForegroundColor(SkColor foreground) {
@@ -231,7 +230,7 @@ void SkiaTextRenderer::DrawPosText(const SkPoint* pos,
const uint16_t* glyphs,
size_t glyph_count) {
SkTextBlobBuilder builder;
- const auto& run_buffer = builder.allocRunPos(flags_.ToSkFont(), glyph_count);
+ const auto& run_buffer = builder.allocRunPos(font_, glyph_count);
static_assert(sizeof(*glyphs) == sizeof(*run_buffer.glyphs), "");
memcpy(run_buffer.glyphs, glyphs, glyph_count * sizeof(*glyphs));
@@ -247,7 +246,7 @@ void SkiaTextRenderer::DrawUnderline(int x,
int width,
SkScalar thickness_factor) {
SkScalar x_scalar = SkIntToScalar(x);
- const SkScalar text_size = flags_.getTextSize();
+ const SkScalar text_size = font_.getSize();
SkRect r = SkRect::MakeLTRB(
x_scalar, y + text_size * kUnderlineOffset, x_scalar + width,
y + (text_size *
@@ -259,7 +258,7 @@ void SkiaTextRenderer::DrawStrike(int x,
int y,
int width,
SkScalar thickness_factor) {
- const SkScalar text_size = flags_.getTextSize();
+ const SkScalar text_size = font_.getSize();
const SkScalar height = text_size * thickness_factor;
const SkScalar top = y - text_size * kStrikeThroughOffset - height / 2;
SkScalar x_scalar = SkIntToScalar(x);
@@ -293,7 +292,7 @@ Range StyleIterator::GetRange() const {
range = range.Intersect(baselines_.GetRange(baseline_));
range = range.Intersect(font_size_overrides_.GetRange(font_size_override_));
range = range.Intersect(weights_.GetRange(weight_));
- for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
+ for (size_t i = 0; i < TEXT_STYLE_COUNT; ++i)
range = range.Intersect(styles_[i].GetRange(style_[i]));
return range;
}
@@ -303,7 +302,7 @@ void StyleIterator::UpdatePosition(size_t position) {
baseline_ = baselines_.GetBreak(position);
font_size_override_ = font_size_overrides_.GetBreak(position);
weight_ = weights_.GetBreak(position);
- for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
+ for (size_t i = 0; i < TEXT_STYLE_COUNT; ++i)
style_[i] = styles_[i].GetBreak(position);
}
@@ -319,14 +318,20 @@ Line::~Line() {}
void ApplyRenderParams(const FontRenderParams& params,
bool subpixel_rendering_suppressed,
- cc::PaintFlags* flags) {
- flags->setAntiAlias(params.antialiasing);
- flags->setLCDRenderText(!subpixel_rendering_suppressed &&
- params.subpixel_rendering !=
- FontRenderParams::SUBPIXEL_RENDERING_NONE);
- flags->setSubpixelText(params.subpixel_positioning);
- flags->setAutohinted(params.autohinter);
- flags->setHinting(FontRenderParamsHintingToPaintFlagsHinting(params.hinting));
+ SkFont* font) {
+ if (!params.antialiasing) {
+ font->setEdging(SkFont::Edging::kAlias);
+ } else if (subpixel_rendering_suppressed ||
+ params.subpixel_rendering ==
+ FontRenderParams::SUBPIXEL_RENDERING_NONE) {
+ font->setEdging(SkFont::Edging::kAntiAlias);
+ } else {
+ font->setEdging(SkFont::Edging::kSubpixelAntiAlias);
+ }
+
+ font->setSubpixel(params.subpixel_positioning);
+ font->setForceAutoHinting(params.autohinter);
+ font->setHinting(FontRenderParamsHintingToSkFontHinting(params.hinting));
}
} // namespace internal
@@ -388,7 +393,7 @@ void RenderText::SetText(const base::string16& text) {
baselines_.SetValue(baselines_.breaks().begin()->second);
font_size_overrides_.SetValue(font_size_overrides_.breaks().begin()->second);
weights_.SetValue(weights_.breaks().begin()->second);
- for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
+ for (size_t style = 0; style < TEXT_STYLE_COUNT; ++style)
styles_[style].SetValue(styles_[style].breaks().begin()->second);
cached_bounds_and_offset_valid_ = false;
@@ -424,9 +429,9 @@ void RenderText::SetFontList(const FontList& font_list) {
font_list_ = font_list;
const int font_style = font_list.GetFontStyle();
weights_.SetValue(font_list.GetFontWeight());
- styles_[ITALIC].SetValue((font_style & Font::ITALIC) != 0);
- styles_[UNDERLINE].SetValue((font_style & Font::UNDERLINE) != 0);
- styles_[HEAVY_UNDERLINE].SetValue(false);
+ styles_[TEXT_STYLE_ITALIC].SetValue((font_style & Font::ITALIC) != 0);
+ styles_[TEXT_STYLE_UNDERLINE].SetValue((font_style & Font::UNDERLINE) != 0);
+ styles_[TEXT_STYLE_HEAVY_UNDERLINE].SetValue(false);
baseline_ = kInvalidBaseline;
cached_bounds_and_offset_valid_ = false;
OnLayoutTextAttributeChanged(false);
@@ -626,8 +631,10 @@ bool RenderText::SetSelection(const SelectionModel& model) {
return changed;
}
-bool RenderText::MoveCursorToPoint(const gfx::Point& point, bool select) {
- gfx::SelectionModel model = FindCursorPosition(point);
+bool RenderText::MoveCursorToPoint(const gfx::Point& point,
+ bool select,
+ const gfx::Point& drag_origin) {
+ gfx::SelectionModel model = FindCursorPosition(point, drag_origin);
if (select)
model.set_selection_start(selection().start());
return SetSelection(model);
@@ -744,7 +751,7 @@ void RenderText::ApplyWeight(Font::Weight weight, const Range& range) {
bool RenderText::GetStyle(TextStyle style) const {
return (styles_[style].breaks().size() == 1) &&
- styles_[style].breaks().front().second;
+ styles_[style].breaks().front().second;
}
void RenderText::SetDirectionalityMode(DirectionalityMode mode) {
@@ -1036,7 +1043,7 @@ RenderText::RenderText()
baselines_(NORMAL_BASELINE),
font_size_overrides_(0),
weights_(Font::Weight::NORMAL),
- styles_(NUM_TEXT_STYLES),
+ styles_(TEXT_STYLE_COUNT),
composition_and_selection_styles_applied_(false),
obscured_(false),
obscured_reveal_index_(-1),
@@ -1059,7 +1066,7 @@ bool RenderText::IsHomogeneous() const {
font_size_overrides().breaks().size() > 1 ||
weights().breaks().size() > 1)
return false;
- for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) {
+ for (size_t style = 0; style < TEXT_STYLE_COUNT; ++style) {
if (styles()[style].breaks().size() > 1)
return false;
}
@@ -1198,11 +1205,11 @@ void RenderText::ApplyCompositionAndSelectionStyles() {
// Save the underline and color breaks to undo the temporary styles later.
DCHECK(!composition_and_selection_styles_applied_);
saved_colors_ = colors_;
- saved_underlines_ = styles_[HEAVY_UNDERLINE];
+ saved_underlines_ = styles_[TEXT_STYLE_HEAVY_UNDERLINE];
// Apply an underline to the composition range in |underlines|.
if (composition_range_.IsValid() && !composition_range_.is_empty())
- styles_[HEAVY_UNDERLINE].ApplyValue(true, composition_range_);
+ styles_[TEXT_STYLE_HEAVY_UNDERLINE].ApplyValue(true, composition_range_);
// Apply the selected text color to the [un-reversed] selection range.
if (!selection().is_empty() && focused()) {
@@ -1216,7 +1223,7 @@ void RenderText::UndoCompositionAndSelectionStyles() {
// Restore the underline and color breaks to undo the temporary styles.
DCHECK(composition_and_selection_styles_applied_);
colors_ = saved_colors_;
- styles_[HEAVY_UNDERLINE] = saved_underlines_;
+ styles_[TEXT_STYLE_HEAVY_UNDERLINE] = saved_underlines_;
composition_and_selection_styles_applied_ = false;
}
@@ -1380,7 +1387,7 @@ void RenderText::UpdateStyleLengths() {
baselines_.SetMax(text_length);
font_size_overrides_.SetMax(text_length);
weights_.SetMax(text_length);
- for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
+ for (size_t style = 0; style < TEXT_STYLE_COUNT; ++style)
styles_[style].SetMax(text_length);
}
@@ -1483,18 +1490,20 @@ void RenderText::OnTextAttributeChanged() {
icu::StringCharacterIterator iter(text.c_str());
// Respect ELIDE_HEAD and ELIDE_MIDDLE preferences during truncation.
if (elide_behavior_ == ELIDE_HEAD) {
- iter.setIndex32(text.length() - truncate_length_ + 1);
+ iter.setIndex32(
+ static_cast<int32_t>(text.length() - truncate_length_ + 1));
layout_text_.assign(kEllipsisUTF16 + text.substr(iter.getIndex()));
} else if (elide_behavior_ == ELIDE_MIDDLE) {
- iter.setIndex32(truncate_length_ / 2);
+ iter.setIndex32(static_cast<int32_t>(truncate_length_ / 2));
const size_t ellipsis_start = iter.getIndex();
- iter.setIndex32(text.length() - (truncate_length_ / 2));
+ iter.setIndex32(
+ static_cast<int32_t>(text.length() - (truncate_length_ / 2)));
const size_t ellipsis_end = iter.getIndex();
DCHECK_LE(ellipsis_start, ellipsis_end);
layout_text_.assign(text.substr(0, ellipsis_start) + kEllipsisUTF16 +
text.substr(ellipsis_end));
} else {
- iter.setIndex32(truncate_length_ - 1);
+ iter.setIndex32(static_cast<int32_t>(truncate_length_ - 1));
layout_text_.assign(text.substr(0, iter.getIndex()) + kEllipsisUTF16);
}
}
@@ -1596,7 +1605,7 @@ base::string16 RenderText::Elide(const base::string16& text,
// Restore styles and baselines without breaking multi-character graphemes.
render_text->styles_ = styles_;
- for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
+ for (size_t style = 0; style < TEXT_STYLE_COUNT; ++style)
RestoreBreakList(render_text.get(), &render_text->styles_[style]);
RestoreBreakList(render_text.get(), &render_text->baselines_);
RestoreBreakList(render_text.get(), &render_text->font_size_overrides_);
@@ -1727,7 +1736,7 @@ size_t RenderText::GetNearestWordStartBoundary(size_t index) const {
// First search for the word start boundary in the CURSOR_BACKWARD direction,
// then in the CURSOR_FORWARD direction.
- for (int i = std::min(index, length - 1); i >= 0; i--)
+ for (int i = static_cast<int>(std::min(index, length - 1)); i >= 0; i--)
if (iter.IsStartOfWord(i))
return i;
diff --git a/chromium/ui/gfx/render_text.h b/chromium/ui/gfx/render_text.h
index 50eaca5b18e..18e57f9823d 100644
--- a/chromium/ui/gfx/render_text.h
+++ b/chromium/ui/gfx/render_text.h
@@ -21,6 +21,7 @@
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/break_list.h"
#include "ui/gfx/font_list.h"
@@ -80,6 +81,7 @@ class GFX_EXPORT SkiaTextRenderer {
Canvas* canvas_;
cc::PaintCanvas* canvas_skia_;
cc::PaintFlags flags_;
+ SkFont font_;
DISALLOW_COPY_AND_ASSIGN(SkiaTextRenderer);
};
@@ -166,10 +168,10 @@ sk_sp<SkTypeface> CreateSkiaTypeface(const Font& font,
bool italic,
Font::Weight weight);
-// Applies the given FontRenderParams to the PaintFlags.
+// Applies the given FontRenderParams to the SkFont.
void ApplyRenderParams(const FontRenderParams& params,
bool subpixel_rendering_suppressed,
- cc::PaintFlags* flags);
+ SkFont* font);
} // namespace internal
@@ -344,8 +346,13 @@ class GFX_EXPORT RenderText {
// Moves the cursor to the text index corresponding to |point|. If |select| is
// true, a selection is made with the current selection start index. If the
// resultant text indices do not lie on valid grapheme boundaries, it is a no-
- // op and returns false.
- bool MoveCursorToPoint(const gfx::Point& point, bool select);
+ // op and returns false. If this move is happening because of a drag causing a
+ // selection change, and |drag_origin| is not the zero point, then
+ // |drag_origin| overrides the default origin for a select-to-drag
+ // (usually the existing text insertion cursor).
+ bool MoveCursorToPoint(const gfx::Point& point,
+ bool select,
+ const gfx::Point& drag_origin = gfx::Point());
// Set the selection_model_ based on |range|.
// If the |range| start or end is greater than text length, it is modified
@@ -446,8 +453,13 @@ class GFX_EXPORT RenderText {
void Draw(Canvas* canvas);
- // Gets the SelectionModel from a visual point in local coordinates.
- virtual SelectionModel FindCursorPosition(const Point& point) = 0;
+ // Gets the SelectionModel from a visual point in local coordinates. If
+ // |drag_origin| is nonzero, it is used as the baseline for
+ // out-of-vertical-bounds drags on platforms that have them, instead of the
+ // default origin (the insertion cursor's position).
+ virtual SelectionModel FindCursorPosition(
+ const Point& point,
+ const Point& drag_origin = gfx::Point()) = 0;
// Returns true if the position is a valid logical index into text(), and is
// also a valid grapheme boundary, which may be used as a cursor position.
diff --git a/chromium/ui/gfx/render_text_harfbuzz.cc b/chromium/ui/gfx/render_text_harfbuzz.cc
index 849a1a88743..b25844a4253 100644
--- a/chromium/ui/gfx/render_text_harfbuzz.cc
+++ b/chromium/ui/gfx/render_text_harfbuzz.cc
@@ -28,6 +28,7 @@
#include "third_party/icu/source/common/unicode/ubidi.h"
#include "third_party/icu/source/common/unicode/utf16.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkFontMetrics.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/decorated_text.h"
@@ -195,10 +196,10 @@ size_t FindRunBreakingCharacter(const base::string16& text,
// Consider 3 characters with the script values {Kana}, {Hira, Kana}, {Kana}.
// Without script extensions only the first script in each set would be taken
// into account, resulting in 3 runs where 1 would be enough.
-int ScriptInterval(const base::string16& text,
- size_t start,
- size_t length,
- UScriptCode* script) {
+size_t ScriptInterval(const base::string16& text,
+ size_t start,
+ size_t length,
+ UScriptCode* script) {
DCHECK_GT(length, 0U);
UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE };
@@ -490,12 +491,12 @@ class HarfBuzzLineBreaker {
line->segments.push_back(segment);
line->size.set_width(line->size.width() + segment.width());
- SkPaint paint;
- paint.setTypeface(run.font_params.skia_face);
- paint.setTextSize(SkIntToScalar(run.font_params.font_size));
- paint.setAntiAlias(run.font_params.render_params.antialiasing);
+ SkFont font(run.font_params.skia_face, run.font_params.font_size);
+ font.setEdging(run.font_params.render_params.antialiasing
+ ? SkFont::Edging::kAntiAlias
+ : SkFont::Edging::kAlias);
SkFontMetrics metrics;
- paint.getFontMetrics(&metrics);
+ font.getMetrics(&metrics);
// max_descent_ is y-down, fDescent is y-down, baseline_offset is y-down
max_descent_ = std::max(max_descent_,
@@ -1100,9 +1101,9 @@ void ShapeRunWithFont(const ShapeRunWithFontInput& in,
// Note that the value of the |item_offset| argument (here specified as
// |in.range.start()|) does affect the result, so we will have to adjust
// the computed offsets.
- hb_buffer_add_utf16(buffer,
- reinterpret_cast<const uint16_t*>(in.text.c_str()),
- in.text.length(), in.range.start(), in.range.length());
+ hb_buffer_add_utf16(
+ buffer, reinterpret_cast<const uint16_t*>(in.text.c_str()),
+ static_cast<int>(in.text.length()), in.range.start(), in.range.length());
hb_buffer_set_script(buffer, ICUScriptToHBScript(in.script));
hb_buffer_set_direction(buffer,
in.is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
@@ -1215,7 +1216,9 @@ SizeF RenderTextHarfBuzz::GetStringSizeF() {
return total_size_;
}
-SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& view_point) {
+SelectionModel RenderTextHarfBuzz::FindCursorPosition(
+ const Point& view_point,
+ const Point& drag_origin) {
EnsureLayout();
DCHECK(!lines().empty());
@@ -1225,7 +1228,9 @@ SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& view_point) {
if (RenderText::kDragToEndIfOutsideVerticalBounds && !multiline() &&
(line_index < 0 || line_index >= static_cast<int>(lines().size()))) {
SelectionModel selection_start = GetSelectionModelForSelectionStart();
- bool left = view_point.x() < GetCursorBounds(selection_start, true).x();
+ int edge = drag_origin.x() == 0 ? GetCursorBounds(selection_start, true).x()
+ : drag_origin.x();
+ bool left = view_point.x() < edge;
return EdgeSelectionModel(left ? CURSOR_LEFT : CURSOR_RIGHT);
}
// Otherwise, clamp |line_index| to a valid value or drag to logical ends.
@@ -1731,12 +1736,12 @@ void RenderTextHarfBuzz::ItemizeTextToRuns(
Range run_range;
internal::TextRunHarfBuzz::FontParams font_params(primary_font);
run_range.set_start(run_break);
- font_params.italic = style.style(ITALIC);
+ font_params.italic = style.style(TEXT_STYLE_ITALIC);
font_params.baseline_type = style.baseline();
font_params.font_size = style.font_size_override();
- font_params.strike = style.style(STRIKE);
- font_params.underline = style.style(UNDERLINE);
- font_params.heavy_underline = style.style(HEAVY_UNDERLINE);
+ font_params.strike = style.style(TEXT_STYLE_STRIKE);
+ font_params.underline = style.style(TEXT_STYLE_UNDERLINE);
+ font_params.heavy_underline = style.style(TEXT_STYLE_HEAVY_UNDERLINE);
font_params.weight = style.weight();
int32_t script_item_break = 0;
bidi_iterator.GetLogicalRun(run_break, &script_item_break,
diff --git a/chromium/ui/gfx/render_text_harfbuzz.h b/chromium/ui/gfx/render_text_harfbuzz.h
index 38a99132b27..97bb64bfc44 100644
--- a/chromium/ui/gfx/render_text_harfbuzz.h
+++ b/chromium/ui/gfx/render_text_harfbuzz.h
@@ -211,7 +211,8 @@ class GFX_EXPORT RenderTextHarfBuzz : public RenderText {
const base::string16& GetDisplayText() override;
Size GetStringSize() override;
SizeF GetStringSizeF() override;
- SelectionModel FindCursorPosition(const Point& point) override;
+ SelectionModel FindCursorPosition(const Point& point,
+ const Point& drag_origin) override;
bool IsSelectionSupported() const override;
std::vector<FontSpan> GetFontSpansForTesting() override;
std::vector<Rect> GetSubstringBounds(const Range& range) override;
diff --git a/chromium/ui/gfx/render_text_mac.h b/chromium/ui/gfx/render_text_mac.h
index 9a952ebc697..1c7f2bbc1e3 100644
--- a/chromium/ui/gfx/render_text_mac.h
+++ b/chromium/ui/gfx/render_text_mac.h
@@ -36,7 +36,8 @@ class GFX_EXPORT RenderTextMac : public RenderText {
const base::string16& GetDisplayText() override;
Size GetStringSize() override;
SizeF GetStringSizeF() override;
- SelectionModel FindCursorPosition(const Point& point) override;
+ SelectionModel FindCursorPosition(const Point& point,
+ const Point& drag_origin) override;
bool IsSelectionSupported() const override;
std::vector<FontSpan> GetFontSpansForTesting() override;
diff --git a/chromium/ui/gfx/render_text_mac.mm b/chromium/ui/gfx/render_text_mac.mm
index 41139a49c0f..bdfb609ab21 100644
--- a/chromium/ui/gfx/render_text_mac.mm
+++ b/chromium/ui/gfx/render_text_mac.mm
@@ -15,8 +15,8 @@
#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "base/strings/sys_string_conversions.h"
#include "skia/ext/skia_utils_mac.h"
#include "third_party/skia/include/ports/SkTypeface_mac.h"
@@ -137,7 +137,8 @@ SizeF RenderTextMac::GetStringSizeF() {
return string_size_;
}
-SelectionModel RenderTextMac::FindCursorPosition(const Point& point) {
+SelectionModel RenderTextMac::FindCursorPosition(const Point& point,
+ const Point& drag_origin) {
// TODO(asvitkine): Implement this. http://crbug.com/131618
return SelectionModel();
}
@@ -317,7 +318,7 @@ base::ScopedCFTypeRef<CTLineRef> RenderTextMac::EnsureLayoutInternal(
const void* keys[] = {kCTFontAttributeName};
const void* values[] = {ct_font};
base::ScopedCFTypeRef<CFDictionaryRef> attributes(
- CFDictionaryCreate(NULL, keys, values, arraysize(keys), NULL,
+ CFDictionaryCreate(NULL, keys, values, base::size(keys), NULL,
&kCFTypeDictionaryValueCallBacks));
base::ScopedCFTypeRef<CFStringRef> cf_text(base::SysUTF16ToCFStringRef(text));
@@ -361,8 +362,9 @@ base::ScopedCFTypeRef<CFMutableArrayRef> RenderTextMac::ApplyStyles(
kCTForegroundColorAttributeName, foreground);
CFArrayAppendValue(attributes, foreground);
- if (style.style(UNDERLINE) || style.style(HEAVY_UNDERLINE)) {
- CTUnderlineStyle value = style.style(HEAVY_UNDERLINE)
+ if (style.style(TEXT_STYLE_UNDERLINE) ||
+ style.style(TEXT_STYLE_HEAVY_UNDERLINE)) {
+ CTUnderlineStyle value = style.style(TEXT_STYLE_HEAVY_UNDERLINE)
? kCTUnderlineStyleThick
: kCTUnderlineStyleSingle;
base::ScopedCFTypeRef<CFNumberRef> underline_value(
@@ -374,7 +376,7 @@ base::ScopedCFTypeRef<CFMutableArrayRef> RenderTextMac::ApplyStyles(
// TODO(mboc): Apply font weights other than bold below.
const int traits =
- (style.style(ITALIC) ? kCTFontItalicTrait : 0) |
+ (style.style(TEXT_STYLE_ITALIC) ? kCTFontItalicTrait : 0) |
(style.weight() >= Font::Weight::BOLD ? kCTFontBoldTrait : 0);
if (traits != 0) {
base::ScopedCFTypeRef<CTFontRef> styled_font =
diff --git a/chromium/ui/gfx/render_text_test_api.h b/chromium/ui/gfx/render_text_test_api.h
index 0abdb2e4740..3fa063a6b2f 100644
--- a/chromium/ui/gfx/render_text_test_api.h
+++ b/chromium/ui/gfx/render_text_test_api.h
@@ -18,11 +18,15 @@ class RenderTextTestApi {
public:
RenderTextTestApi(RenderText* render_text) : render_text_(render_text) {}
- static cc::PaintFlags& GetRendererPaint(
+ static const cc::PaintFlags& GetRendererPaint(
internal::SkiaTextRenderer* renderer) {
return renderer->flags_;
}
+ static const SkFont& GetRendererFont(internal::SkiaTextRenderer* renderer) {
+ return renderer->font_;
+ }
+
// Callers must ensure that the associated RenderText object is a
// RenderTextHarfBuzz instance.
const internal::TextRunList* GetHarfBuzzRunList() const {
diff --git a/chromium/ui/gfx/render_text_unittest.cc b/chromium/ui/gfx/render_text_unittest.cc
index 2ae6bf4375d..c8957cfb537 100644
--- a/chromium/ui/gfx/render_text_unittest.cc
+++ b/chromium/ui/gfx/render_text_unittest.cc
@@ -14,8 +14,8 @@
#include "base/format_macros.h"
#include "base/i18n/break_iterator.h"
-#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -69,9 +69,9 @@ const char kRtlLtrRtl[] = "\u05d0a\u05d1";
// Bitmasks based on gfx::TextStyle.
enum {
- ITALIC_MASK = 1 << ITALIC,
- STRIKE_MASK = 1 << STRIKE,
- UNDERLINE_MASK = 1 << UNDERLINE,
+ ITALIC_MASK = 1 << TEXT_STYLE_ITALIC,
+ STRIKE_MASK = 1 << TEXT_STYLE_STRIKE,
+ UNDERLINE_MASK = 1 << TEXT_STYLE_UNDERLINE,
};
// Checks whether |range| contains |index|. This is not the same as calling
@@ -333,10 +333,14 @@ class RenderTextTest : public testing::Test {
renderer_(canvas()) {}
protected:
- cc::PaintFlags& GetRendererPaint() {
+ const cc::PaintFlags& GetRendererPaint() {
return test::RenderTextTestApi::GetRendererPaint(renderer());
}
+ const SkFont& GetRendererFont() {
+ return test::RenderTextTestApi::GetRendererFont(renderer());
+ }
+
void DrawVisualText() { test_api_->DrawVisualText(renderer()); }
const internal::TextRunList* GetHarfBuzzRunList() const {
@@ -500,11 +504,11 @@ TEST_F(RenderTextTest, DefaultStyles) {
RenderText* render_text = GetRenderText();
EXPECT_TRUE(render_text->text().empty());
const char* const cases[] = {kWeak, kLtr, "Hello", kRtl, "", ""};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(SK_ColorBLACK));
EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(NORMAL_BASELINE));
EXPECT_TRUE(test_api()->font_size_overrides().EqualsValueForTesting(0));
- for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
+ for (size_t style = 0; style < static_cast<int>(TEXT_STYLE_COUNT); ++style)
EXPECT_TRUE(test_api()->styles()[style].EqualsValueForTesting(false));
render_text->SetText(UTF8ToUTF16(cases[i]));
}
@@ -517,21 +521,24 @@ TEST_F(RenderTextTest, SetStyles) {
render_text->SetColor(color);
render_text->SetBaselineStyle(SUPERSCRIPT);
render_text->SetWeight(Font::Weight::BOLD);
- render_text->SetStyle(UNDERLINE, false);
+ render_text->SetStyle(TEXT_STYLE_UNDERLINE, false);
const char* const cases[] = {kWeak, kLtr, "Hello", kRtl, "", ""};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(color));
EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(SUPERSCRIPT));
EXPECT_TRUE(
test_api()->weights().EqualsValueForTesting(Font::Weight::BOLD));
- EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsValueForTesting(false));
+ EXPECT_TRUE(
+ test_api()->styles()[TEXT_STYLE_UNDERLINE].EqualsValueForTesting(
+ false));
render_text->SetText(UTF8ToUTF16(cases[i]));
// Ensure custom default styles can be applied after text has been set.
if (i == 1)
- render_text->SetStyle(STRIKE, true);
+ render_text->SetStyle(TEXT_STYLE_STRIKE, true);
if (i >= 1)
- EXPECT_TRUE(test_api()->styles()[STRIKE].EqualsValueForTesting(true));
+ EXPECT_TRUE(
+ test_api()->styles()[TEXT_STYLE_STRIKE].EqualsValueForTesting(true));
}
}
@@ -583,32 +590,37 @@ TEST_F(RenderTextTest, ApplyStyles) {
{{0, Font::Weight::NORMAL}, {2, Font::Weight::BOLD}}));
// Ensure ranged values adjust to accommodate text length changes.
- render_text->ApplyStyle(ITALIC, true, Range(0, 2));
- render_text->ApplyStyle(ITALIC, true, Range(3, 6));
- render_text->ApplyStyle(ITALIC, true, Range(7, text_length));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(0, 2));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(3, 6));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(7, text_length));
std::vector<std::pair<size_t, bool>> expected_italic = {
{0, true}, {2, false}, {3, true}, {6, false}, {7, true}};
- EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
+ EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting(
+ expected_italic));
// Changing the text should clear any breaks except for the first one.
render_text->SetText(UTF8ToUTF16("0123456"));
expected_italic.resize(1);
- EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
- render_text->ApplyStyle(ITALIC, false, Range(2, 4));
+ EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting(
+ expected_italic));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, false, Range(2, 4));
render_text->SetText(UTF8ToUTF16("012345678"));
- EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
- render_text->ApplyStyle(ITALIC, false, Range(0, 1));
+ EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting(
+ expected_italic));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, false, Range(0, 1));
render_text->SetText(UTF8ToUTF16("0123456"));
expected_italic.begin()->second = false;
- EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
- render_text->ApplyStyle(ITALIC, true, Range(2, 4));
+ EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting(
+ expected_italic));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(2, 4));
render_text->SetText(UTF8ToUTF16("012345678"));
- EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
+ EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting(
+ expected_italic));
// 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(
+ render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(2, 5));
+ EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_UNDERLINE].EqualsForTesting(
{{0, false}, {1, true}, {6, false}}));
}
@@ -618,7 +630,7 @@ TEST_F(RenderTextTest, AppendTextKeepsStyles) {
render_text->SetText(UTF8ToUTF16("abcd"));
render_text->ApplyColor(SK_ColorRED, Range(0, 1));
render_text->ApplyBaselineStyle(SUPERSCRIPT, Range(1, 2));
- render_text->ApplyStyle(UNDERLINE, true, Range(2, 3));
+ render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(2, 3));
render_text->ApplyFontSizeOverride(20, Range(3, 4));
// Verify basic functionality.
const std::vector<std::pair<size_t, SkColor>> expected_color = {
@@ -629,7 +641,8 @@ TEST_F(RenderTextTest, AppendTextKeepsStyles) {
EXPECT_TRUE(test_api()->baselines().EqualsForTesting(expected_baseline));
const std::vector<std::pair<size_t, bool>> expected_style = {
{0, false}, {2, true}, {3, false}};
- EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(expected_style));
+ EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_UNDERLINE].EqualsForTesting(
+ expected_style));
const std::vector<std::pair<size_t, int>> expected_font_size = {{0, 0},
{3, 20}};
EXPECT_TRUE(
@@ -640,7 +653,8 @@ TEST_F(RenderTextTest, AppendTextKeepsStyles) {
EXPECT_EQ(render_text->GetDisplayText(), UTF8ToUTF16("abcdefg"));
EXPECT_TRUE(test_api()->colors().EqualsForTesting(expected_color));
EXPECT_TRUE(test_api()->baselines().EqualsForTesting(expected_baseline));
- EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(expected_style));
+ EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_UNDERLINE].EqualsForTesting(
+ expected_style));
EXPECT_TRUE(
test_api()->font_size_overrides().EqualsForTesting(expected_font_size));
}
@@ -736,7 +750,7 @@ TEST_F(RenderTextTest, ObscuredText) {
"hop on pop", // Check LTR word boundaries.
"\u05d0\u05d1 \u05d0\u05d2 \u05d1\u05d2", // Check RTL word boundaries.
};
- for (size_t i = 0; i < arraysize(texts); ++i) {
+ for (size_t i = 0; i < base::size(texts); ++i) {
base::string16 text = UTF8ToUTF16(texts[i]);
TestVisualCursorMotionInObscuredField(render_text, text, SELECTION_NONE);
TestVisualCursorMotionInObscuredField(render_text, text, SELECTION_RETAIN);
@@ -904,7 +918,7 @@ TEST_F(RenderTextTest, ElidedText) {
render_text->SetFontList(FontList("serif, Sans serif, 12px"));
render_text->SetElideBehavior(ELIDE_TAIL);
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "] '%ls'", i,
cases[i].text));
@@ -957,7 +971,7 @@ TEST_F(RenderTextTest, MultilineElide) {
// with these styles. This can expose a behavior in layout where text is
// slightly different width. This must be done after |SetText()|.
render_text->ApplyWeight(Font::Weight::BOLD, Range(1, 20));
- render_text->ApplyStyle(ITALIC, true, Range(1, 20));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(1, 20));
render_text->SetMultiline(true);
render_text->SetElideBehavior(ELIDE_TAIL);
render_text->SetMaxLines(3);
@@ -1006,7 +1020,7 @@ TEST_F(RenderTextTest, MultilineElideWrap) {
render_text->SetText(input_text);
render_text->ApplyWeight(Font::Weight::BOLD, Range(1, 20));
- render_text->ApplyStyle(ITALIC, true, Range(1, 20));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(1, 20));
render_text->SetMultiline(true);
render_text->SetMaxLines(3);
render_text->SetElideBehavior(ELIDE_TAIL);
@@ -1122,7 +1136,7 @@ TEST_F(RenderTextTest, TruncatedText) {
RenderText* render_text = GetRenderText();
render_text->set_truncate_length(5);
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
render_text->SetText(WideToUTF16(cases[i].text));
EXPECT_EQ(WideToUTF16(cases[i].text), render_text->text());
EXPECT_EQ(WideToUTF16(cases[i].display_text), render_text->GetDisplayText())
@@ -1554,7 +1568,7 @@ TEST_F(RenderTextTest, GetDisplayTextDirection) {
base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
// Ensure that directionality modes yield the correct text directions.
- for (size_t j = 0; j < arraysize(cases); j++) {
+ for (size_t j = 0; j < base::size(cases); j++) {
render_text->SetText(UTF8ToUTF16(cases[j].text));
render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
EXPECT_EQ(render_text->GetDisplayTextDirection(),cases[j].text_direction);
@@ -1827,7 +1841,7 @@ TEST_F(RenderTextTest, GraphemePositions) {
};
RenderText* render_text = GetRenderText();
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
render_text->SetText(cases[i].text);
@@ -1851,7 +1865,7 @@ TEST_F(RenderTextTest, MidGraphemeSelectionBounds) {
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(100, 1000));
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
render_text->SetText(cases[i]);
EXPECT_TRUE(render_text->IsValidLogicalIndex(1));
@@ -1881,7 +1895,7 @@ TEST_F(RenderTextTest, FindCursorPosition) {
const char* kTestStrings[] = {kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl};
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(0, 0, 100, 20));
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
for (size_t j = 0; j < render_text->text().length(); ++j) {
@@ -1905,7 +1919,7 @@ TEST_F(RenderTextTest, FindCursorPositionMultiline) {
render_text->SetDisplayRect(Rect(25, 1000));
render_text->SetMultiline(true);
- for (size_t i = 0; i < arraysize(kTestStrings); i++) {
+ for (size_t i = 0; i < base::size(kTestStrings); i++) {
render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
test_api()->EnsureLayout();
EXPECT_EQ(2u, test_api()->lines().size());
@@ -1947,7 +1961,7 @@ TEST_F(RenderTextTest, FindCursorPosition_GraphemeBoundaries) {
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(gfx::Rect(100, 30));
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing case %" PRIuS "", i));
render_text->SetText(cases[i].text);
test_api()->EnsureLayout();
@@ -1985,7 +1999,7 @@ TEST_F(RenderTextTest, EdgeSelectionModels) {
};
RenderText* render_text = GetRenderText();
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
render_text->SetText(cases[i].text);
bool ltr = (cases[i].expected_text_direction == base::i18n::LEFT_TO_RIGHT);
@@ -2017,7 +2031,7 @@ TEST_F(RenderTextTest, SelectAll) {
EXPECT_EQ(render_text->selection_model(), SelectionModel());
// Test the weak, LTR, RTL, and Bidi string cases.
- for (size_t j = 0; j < arraysize(cases); j++) {
+ for (size_t j = 0; j < base::size(cases); j++) {
render_text->SetText(UTF8ToUTF16(cases[j]));
render_text->SelectAll(false);
EXPECT_EQ(render_text->selection_model(), expected_forwards);
@@ -2637,7 +2651,7 @@ TEST_F(RenderTextTest, StringSizeHeight) {
const FontList& larger_font_list = default_font_list.DeriveWithSizeDelta(24);
EXPECT_GT(larger_font_list.GetHeight(), default_font_list.GetHeight());
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
ResetRenderTextInstance();
RenderText* render_text = GetRenderText();
render_text->SetFontList(default_font_list);
@@ -2781,7 +2795,7 @@ TEST_F(RenderTextTest, SetDisplayOffset) {
{ ALIGN_CENTER, kEnlargement },
};
- for (size_t i = 0; i < arraysize(small_content_cases); i++) {
+ for (size_t i = 0; i < base::size(small_content_cases); i++) {
render_text->SetHorizontalAlignment(small_content_cases[i].alignment);
render_text->SetDisplayOffset(small_content_cases[i].offset);
EXPECT_EQ(0, render_text->GetUpdatedDisplayOffset().x());
@@ -2816,7 +2830,7 @@ TEST_F(RenderTextTest, SetDisplayOffset) {
{ ALIGN_CENTER, kEnlargement, (kEnlargement - 1) / 2 },
};
- for (size_t i = 0; i < arraysize(large_content_cases); i++) {
+ for (size_t i = 0; i < base::size(large_content_cases); i++) {
render_text->SetHorizontalAlignment(large_content_cases[i].alignment);
render_text->SetDisplayOffset(large_content_cases[i].offset);
EXPECT_EQ(large_content_cases[i].expected_offset,
@@ -2864,14 +2878,14 @@ TEST_F(RenderTextTest, SameFontForParentheses) {
};
RenderText* render_text = GetRenderText();
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
base::string16 text = cases[i].text;
const size_t start_paren_char_index = text.find('(');
ASSERT_NE(base::string16::npos, start_paren_char_index);
const size_t end_paren_char_index = text.find(')');
ASSERT_NE(base::string16::npos, end_paren_char_index);
- for (size_t j = 0; j < arraysize(punctuation_pairs); ++j) {
+ for (size_t j = 0; j < base::size(punctuation_pairs); ++j) {
text[start_paren_char_index] = punctuation_pairs[j].left_char;
text[end_paren_char_index] = punctuation_pairs[j].right_char;
render_text->SetText(text);
@@ -2935,7 +2949,7 @@ TEST_F(RenderTextTest, SelectWord) {
{ 16, 13, 16 },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
render_text->SetCursorPosition(cases[i].cursor);
render_text->SelectWord();
EXPECT_EQ(Range(cases[i].selection_start, cases[i].selection_end),
@@ -3106,7 +3120,7 @@ TEST_F(RenderTextTest, SelectionKeepsLigatures) {
RenderText* render_text = GetRenderText();
render_text->set_selection_color(SK_ColorRED);
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
const int expected_width = render_text->GetStringSize().width();
render_text->SelectRange({0, 1});
@@ -3168,7 +3182,7 @@ TEST_F(RenderTextTest, Multiline_MinWidth) {
render_text->SetMultiline(true);
render_text->SetWordWrapBehavior(WRAP_LONG_WORDS);
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
render_text->Draw(canvas());
@@ -3225,7 +3239,7 @@ TEST_F(RenderTextTest, Multiline_NormalWidth) {
render_text->SetWordWrapBehavior(WRAP_LONG_WORDS);
render_text->SetHorizontalAlignment(ALIGN_TO_HEAD);
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(UTF8ToUTF16(kTestStrings[i].text));
DrawVisualText();
@@ -3270,7 +3284,7 @@ TEST_F(RenderTextTest, Multiline_SufficientWidth) {
render_text->SetDisplayRect(Rect(1000, 1000));
render_text->SetMultiline(true);
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
render_text->Draw(canvas());
@@ -3297,7 +3311,7 @@ TEST_F(RenderTextTest, Multiline_Newline) {
render_text->SetDisplayRect(Rect(200, 1000));
render_text->SetMultiline(true);
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(UTF8ToUTF16(kTestStrings[i].text));
render_text->Draw(canvas());
@@ -3343,7 +3357,7 @@ TEST_F(RenderTextTest, Multiline_NewlineCharacterReplacement) {
"abc\ndef", "a \n b ", "ab\n", "a\n\nb", "\nab", "\n",
};
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
ResetRenderTextInstance();
RenderText* render_text = GetRenderText();
@@ -3399,7 +3413,7 @@ TEST_F(RenderTextTest, Multiline_HorizontalAlignment) {
render_text->SetDisplayRect(Rect(100, 1000));
render_text->SetMultiline(true);
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(testing::Message("kTestStrings[")
<< i << "] = " << kTestStrings[i].text);
render_text->SetText(UTF8ToUTF16(kTestStrings[i].text));
@@ -3453,7 +3467,7 @@ TEST_F(RenderTextTest, Multiline_WordWrapBehavior) {
SetGlyphWidth(kGlyphSize);
render_text->SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0));
- for (size_t i = 0; i < arraysize(kTestScenarios); ++i) {
+ for (size_t i = 0; i < base::size(kTestScenarios); ++i) {
SCOPED_TRACE(base::StringPrintf(
"kTestScenarios[%" PRIuS "] %d", i, kTestScenarios[i].behavior));
render_text->SetWordWrapBehavior(kTestScenarios[i].behavior);
@@ -3511,7 +3525,7 @@ TEST_F(RenderTextTest, Multiline_LineBreakerBehavior) {
SetGlyphWidth(kGlyphSize);
render_text->SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0));
- for (size_t i = 0; i < arraysize(kTestScenarios); ++i) {
+ for (size_t i = 0; i < base::size(kTestScenarios); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(UTF8ToUTF16(kTestScenarios[i].text));
render_text->SetWordWrapBehavior(kTestScenarios[i].behavior);
@@ -3574,7 +3588,7 @@ TEST_F(RenderTextTest, Multiline_SurrogatePairsOrCombiningChars) {
{ Range(0, 2), Range(2, 3), Range(3, 5) } },
};
- for (size_t i = 0; i < arraysize(kTestScenarios); ++i) {
+ for (size_t i = 0; i < base::size(kTestScenarios); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestScenarios[i].text);
render_text->SetDisplayRect(Rect(0, 0, kTestScenarios[i].display_width, 0));
@@ -3618,7 +3632,7 @@ TEST_F(RenderTextTest, Multiline_ZeroWidthChars) {
EXPECT_EQ(3u, test_api()->lines().size());
for (size_t j = 0;
- j < std::min(arraysize(char_ranges), test_api()->lines().size()); ++j) {
+ j < std::min(base::size(char_ranges), test_api()->lines().size()); ++j) {
SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j));
int segment_size = test_api()->lines()[j].segments.size();
ASSERT_GT(segment_size, 0);
@@ -3637,7 +3651,7 @@ TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) {
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(200, 1000));
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
render_text->Draw(canvas());
@@ -3659,7 +3673,7 @@ TEST_F(RenderTextTest, HarfBuzz_HorizontalPositions) {
RenderTextHarfBuzz* render_text = GetRenderText();
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(UTF8ToUTF16(kTestStrings[i].text));
@@ -3726,7 +3740,7 @@ TEST_F(RenderTextTest, HarfBuzz_Clusters) {
run.shape.glyph_count = 4;
run.shape.glyph_to_char.resize(4);
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4,
run.shape.glyph_to_char.begin());
run.font_params.is_rtl = cases[i].is_rtl;
@@ -3769,7 +3783,7 @@ TEST_F(RenderTextTest, HarfBuzz_SubglyphGraphemeCases) {
RenderTextHarfBuzz* render_text = GetRenderText();
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
SCOPED_TRACE(base::StringPrintf("Case %" PRIuS, i));
base::string16 text = UTF8ToUTF16(cases[i]);
@@ -3825,7 +3839,7 @@ TEST_F(RenderTextTest, HarfBuzz_SubglyphGraphemePartition) {
RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abcd"));
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 2,
run.shape.glyph_to_char.begin());
run.font_params.is_rtl = cases[i].is_rtl;
@@ -4141,7 +4155,7 @@ TEST_F(RenderTextTest, GlyphBounds) {
"\u0645\u0631\u062D\u0628\u0627"};
RenderText* render_text = GetRenderText();
- for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ for (size_t i = 0; i < base::size(kTestStrings); ++i) {
render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
test_api()->EnsureLayout();
@@ -4460,21 +4474,21 @@ TEST_F(RenderTextTest, StylePropagated) {
DrawVisualText();
EXPECT_EQ(SkFontStyle::Normal(),
- GetRendererPaint().getTypeface()->fontStyle());
+ GetRendererFont().getTypeface()->fontStyle());
render_text->SetWeight(Font::Weight::BOLD);
DrawVisualText();
- EXPECT_EQ(SkFontStyle::Bold(), GetRendererPaint().getTypeface()->fontStyle());
+ EXPECT_EQ(SkFontStyle::Bold(), GetRendererFont().getTypeface()->fontStyle());
- render_text->SetStyle(TextStyle::ITALIC, true);
+ render_text->SetStyle(TEXT_STYLE_ITALIC, true);
DrawVisualText();
EXPECT_EQ(SkFontStyle::BoldItalic(),
- GetRendererPaint().getTypeface()->fontStyle());
+ GetRendererFont().getTypeface()->fontStyle());
render_text->SetWeight(Font::Weight::NORMAL);
DrawVisualText();
EXPECT_EQ(SkFontStyle::Italic(),
- GetRendererPaint().getTypeface()->fontStyle());
+ GetRendererFont().getTypeface()->fontStyle());
}
// Ensure the painter adheres to RenderText::subpixel_rendering_suppressed().
@@ -4493,7 +4507,7 @@ TEST_F(RenderTextTest, SubpixelRenderingSuppressed) {
FontRenderParams::SUBPIXEL_RENDERING_RGB;
DrawVisualText();
#endif
- EXPECT_TRUE(GetRendererPaint().isLCDRenderText());
+ EXPECT_EQ(GetRendererFont().getEdging(), SkFont::Edging::kSubpixelAntiAlias);
render_text->set_subpixel_rendering_suppressed(true);
DrawVisualText();
@@ -4501,21 +4515,19 @@ TEST_F(RenderTextTest, SubpixelRenderingSuppressed) {
// For Linux, runs shouldn't be re-calculated, and the suppression of the
// SUBPIXEL_RENDERING_RGB set above should now take effect. But, after
// checking, apply the override anyway to be explicit that it is suppressed.
- EXPECT_FALSE(GetRendererPaint().isLCDRenderText());
+ EXPECT_NE(GetRendererFont().getEdging(), SkFont::Edging::kSubpixelAntiAlias);
GetHarfBuzzRunList()
->runs()[0]
->font_params.render_params.subpixel_rendering =
FontRenderParams::SUBPIXEL_RENDERING_RGB;
DrawVisualText();
#endif
- EXPECT_FALSE(GetRendererPaint().isLCDRenderText());
+ EXPECT_NE(GetRendererFont().getEdging(), SkFont::Edging::kSubpixelAntiAlias);
}
// Ensure the SkFont Edging is computed accurately.
TEST_F(RenderTextTest, SkFontEdging) {
- const auto edging = [this]() {
- return GetRendererPaint().ToSkFont().getEdging();
- };
+ const auto edging = [this]() { return GetRendererFont().getEdging(); };
FontRenderParams params;
EXPECT_TRUE(params.antialiasing);
@@ -4563,9 +4575,9 @@ TEST_F(RenderTextTest, GetWordLookupDataAtPoint_LTR) {
render_text->SetDisplayRect(Rect(100, 30));
render_text->SetText(ltr);
render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(0, 3));
- render_text->ApplyStyle(UNDERLINE, true, Range(1, 5));
- render_text->ApplyStyle(ITALIC, true, Range(3, 8));
- render_text->ApplyStyle(STRIKE, true, Range(1, 7));
+ render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(1, 5));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(3, 8));
+ render_text->ApplyStyle(TEXT_STYLE_STRIKE, true, Range(1, 7));
const int cursor_y = GetCursorYForTesting();
const std::vector<RenderText::FontSpan> font_spans =
@@ -4643,9 +4655,9 @@ TEST_F(RenderTextTest, GetWordLookupDataAtPoint_RTL) {
render_text->SetDisplayRect(Rect(100, 30));
render_text->SetText(rtl);
render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(2, 3));
- render_text->ApplyStyle(UNDERLINE, true, Range(3, 6));
- render_text->ApplyStyle(ITALIC, true, Range(0, 3));
- render_text->ApplyStyle(STRIKE, true, Range(2, 5));
+ render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(3, 6));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(0, 3));
+ render_text->ApplyStyle(TEXT_STYLE_STRIKE, true, Range(2, 5));
const int cursor_y = GetCursorYForTesting();
const std::vector<RenderText::FontSpan> font_spans =
@@ -4724,9 +4736,9 @@ TEST_F(RenderTextTest, GetWordLookupDataAtPoint_Multiline) {
render_text->SetDisplayRect(Rect(500, 500));
render_text->SetText(text);
render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(0, 3));
- render_text->ApplyStyle(UNDERLINE, true, Range(1, 7));
- render_text->ApplyStyle(STRIKE, true, Range(1, 8));
- render_text->ApplyStyle(ITALIC, true, Range(5, 9));
+ render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(1, 7));
+ render_text->ApplyStyle(TEXT_STYLE_STRIKE, true, Range(1, 8));
+ render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(5, 9));
// Set up test expectations.
const std::vector<RenderText::FontSpan> font_spans =
@@ -4833,7 +4845,7 @@ TEST_F(RenderTextTest, GetLookupDataAtRange_Multiline) {
render_text->SetDisplayRect(Rect(500, 500));
render_text->SetText(text);
render_text->ApplyWeight(Font::Weight::SEMIBOLD, kWordOneRange);
- render_text->ApplyStyle(UNDERLINE, true, kWordTwoRange);
+ render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, kWordTwoRange);
// Set up test expectations.
const std::vector<RenderText::FontSpan> font_spans =
@@ -4916,7 +4928,7 @@ TEST_F(RenderTextTest, LineEndSelections) {
render_text->SetMultiline(true);
render_text->SetDisplayRect(Rect(200, 1000));
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing case %" PRIuS "", i));
render_text->SetText(UTF8ToUTF16(cases[i].text));
test_api()->EnsureLayout();
diff --git a/chromium/ui/gfx/rrect_f.cc b/chromium/ui/gfx/rrect_f.cc
new file mode 100644
index 00000000000..4a8bf0666b3
--- /dev/null
+++ b/chromium/ui/gfx/rrect_f.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/gfx/rrect_f.h"
+
+#include <iomanip>
+#include <iostream>
+
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+
+namespace gfx {
+
+gfx::Vector2dF RRectF::GetSimpleRadii() const {
+ DCHECK(GetType() <= Type::kOval);
+ SkPoint result = skrrect_.getSimpleRadii();
+ return gfx::Vector2dF(result.x(), result.y());
+}
+
+float RRectF::GetSimpleRadius() const {
+ DCHECK(GetType() <= Type::kSingle);
+ SkPoint result = skrrect_.getSimpleRadii();
+ return result.x();
+}
+
+RRectF::Type RRectF::GetType() const {
+ SkPoint rad;
+ switch (skrrect_.getType()) {
+ case SkRRect::kEmpty_Type:
+ return Type::kEmpty;
+ case SkRRect::kRect_Type:
+ return Type::kRect;
+ case SkRRect::kSimple_Type:
+ rad = skrrect_.getSimpleRadii();
+ if (rad.x() == rad.y()) {
+ return Type::kSingle;
+ }
+ return Type::kSimple;
+ case SkRRect::kOval_Type:
+ return Type::kOval;
+ case SkRRect::kNinePatch_Type:
+ case SkRRect::kComplex_Type:
+ default:
+ return Type::kComplex;
+ };
+}
+
+gfx::Vector2dF RRectF::GetCornerRadii(Corner corner) const {
+ SkPoint result = skrrect_.radii(SkRRect::Corner(corner));
+ return gfx::Vector2dF(result.x(), result.y());
+}
+
+void RRectF::GetAllRadii(SkVector radii[4]) const {
+ // Unfortunately, the only way to get all radii is one at a time.
+ radii[SkRRect::kUpperLeft_Corner] =
+ skrrect_.radii(SkRRect::kUpperLeft_Corner);
+ radii[SkRRect::kUpperRight_Corner] =
+ skrrect_.radii(SkRRect::kUpperRight_Corner);
+ radii[SkRRect::kLowerRight_Corner] =
+ skrrect_.radii(SkRRect::kLowerRight_Corner);
+ radii[SkRRect::kLowerLeft_Corner] =
+ skrrect_.radii(SkRRect::kLowerLeft_Corner);
+}
+
+void RRectF::SetCornerRadii(Corner corner, float x_rad, float y_rad) {
+ // Unfortunately, the only way to set this is to create a new SkRRect.
+ SkVector radii[4];
+ GetAllRadii(radii);
+ radii[SkRRect::Corner(corner)] = SkPoint::Make(x_rad, y_rad);
+ skrrect_.setRectRadii(skrrect_.rect(), radii);
+}
+
+void RRectF::Scale(float x_scale, float y_scale) {
+ SkMatrix scale = SkMatrix::MakeScale(x_scale, y_scale);
+ SkRRect result;
+ bool success = skrrect_.transform(scale, &result);
+ DCHECK(success);
+ skrrect_ = result;
+}
+
+void RRectF::Offset(float horizontal, float vertical) {
+ skrrect_.offset(horizontal, vertical);
+}
+
+const RRectF& RRectF::operator+=(const gfx::Vector2dF& offset) {
+ Offset(offset.x(), offset.y());
+ return *this;
+}
+
+const RRectF& RRectF::operator-=(const gfx::Vector2dF& offset) {
+ Offset(-offset.x(), -offset.y());
+ return *this;
+}
+
+std::string RRectF::ToString() const {
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(3);
+ ss << rect().origin().x() << "," << rect().origin().y() << " "
+ << rect().size().width() << "x" << rect().size().height();
+ Type type = this->GetType();
+ if (type <= Type::kRect) {
+ ss << ", rectangular";
+ } else if (type <= Type::kSingle) {
+ ss << ", radius " << GetSimpleRadius();
+ } else if (type <= Type::kSimple) {
+ gfx::Vector2dF radii = GetSimpleRadii();
+ ss << ", x_rad " << radii.x() << ", y_rad " << radii.y();
+ } else {
+ ss << ",";
+ const Corner corners[] = {Corner::kUpperLeft, Corner::kUpperRight,
+ Corner::kLowerRight, Corner::kLowerLeft};
+ for (const auto& c : corners) {
+ auto this_corner = GetCornerRadii(c);
+ ss << " [" << this_corner.x() << " " << this_corner.y() << "]";
+ }
+ }
+ return ss.str();
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/rrect_f.h b/chromium/ui/gfx/rrect_f.h
new file mode 100644
index 00000000000..536f8bde0c2
--- /dev/null
+++ b/chromium/ui/gfx/rrect_f.h
@@ -0,0 +1,153 @@
+// 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_RRECT_F_H_
+#define UI_GFX_RRECT_F_H_
+
+#include <memory>
+#include <string>
+
+#include "third_party/skia/include/core/SkRRect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/skia_util.h"
+
+namespace gfx {
+
+class GEOMETRY_SKIA_EXPORT RRectF {
+ public:
+ RRectF() = default;
+ ~RRectF() = default;
+ RRectF(const RRectF& rect) = default;
+ RRectF& operator=(const RRectF& rect) = default;
+ explicit RRectF(const SkRRect& rect) : skrrect_(rect) {}
+ explicit RRectF(const gfx::RectF& rect) : RRectF(rect, 0.f) {}
+ RRectF(const gfx::RectF& rect, float radius) : RRectF(rect, radius, radius) {}
+ RRectF(const gfx::RectF& rect, float x_rad, float y_rad)
+ : RRectF(rect.x(), rect.y(), rect.width(), rect.height(), x_rad, y_rad) {}
+ // Sets all x and y radii to radius.
+ RRectF(float x, float y, float width, float height, float radius)
+ : RRectF(x, y, width, height, radius, radius) {}
+ // Sets all x radii to x_rad, and all y radii to y_rad. If one of x_rad or
+ // y_rad are zero, sets ALL radii to zero.
+ RRectF(float x, float y, float width, float height, float x_rad, float y_rad)
+ : skrrect_(SkRRect::MakeRectXY(SkRect::MakeXYWH(x, y, width, height),
+ x_rad,
+ y_rad)) {}
+
+ // The rectangular portion of the RRectF, without the corner radii.
+ gfx::RectF rect() const { return gfx::SkRectToRectF(skrrect_.rect()); }
+
+ // Returns the radii of the all corners. DCHECKs that all corners
+ // have the same radii (the type is <= kOval).
+ gfx::Vector2dF GetSimpleRadii() const;
+ // Returns the radius of all corners. DCHECKs that all corners have the same
+ // radii, and that x_rad == y_rad (the type is <= kSingle).
+ float GetSimpleRadius() const;
+
+ // Make the RRectF empty.
+ void Clear() { skrrect_.setEmpty(); }
+
+ bool Equals(const RRectF& other) const { return skrrect_ == other.skrrect_; }
+
+ // These are all mutually exclusive, and ordered in increasing complexity. The
+ // order is assumed in several functions.
+ enum class Type {
+ kEmpty, // Zero width or height.
+ kRect, // Non-zero width and height, and zeroed radii - a pure rectangle.
+ kSingle, // Non-zero width and height, and a single, non-zero value for all
+ // X and Y radii.
+ kSimple, // Non-zero width and height, X radii all equal and non-zero, Y
+ // radii all equal and non-zero, and x_rad != y_rad.
+ kOval, // Non-zero width and height, X radii all equal to width/2, and Y
+ // radii all equal to height/2.
+ kComplex, // Non-zero width and height, and arbitrary (non-equal) radii.
+ };
+ Type GetType() const;
+
+ bool IsEmpty() const { return GetType() == Type::kEmpty; }
+
+ enum class Corner {
+ kUpperLeft = SkRRect::kUpperLeft_Corner,
+ kUpperRight = SkRRect::kUpperRight_Corner,
+ kLowerRight = SkRRect::kLowerRight_Corner,
+ kLowerLeft = SkRRect::kLowerLeft_Corner,
+ };
+ // GetCornerRadii may be called for any type of RRect (kRect, kOval, etc.),
+ // and it will return "correct" values. If GetType() is kOval or less, all
+ // corner values will be identical to each other. SetCornerRadii can similarly
+ // be called on any type of RRect, but GetType() may change as a result of the
+ // call.
+ gfx::Vector2dF GetCornerRadii(Corner corner) const;
+ void SetCornerRadii(Corner corner, float x_rad, float y_rad);
+ void SetCornerRadii(Corner corner, const gfx::Vector2dF& radii) {
+ SetCornerRadii(corner, radii.x(), radii.y());
+ }
+
+ // Returns true if |rect| is inside the bounds and corner radii of this
+ // RRectF, and if both this RRectF and rect are not empty.
+ bool Contains(const RectF& rect) const {
+ return skrrect_.contains(gfx::RectFToSkRect(rect));
+ }
+
+ // Scales the rectangle by |scale|.
+ void Scale(float scale) { Scale(scale, scale); }
+ // Scales the rectangle by |x_scale| and |y_scale|.
+ void Scale(float x_scale, float y_scale);
+
+ // Move the rectangle by a horizontal and vertical distance.
+ void Offset(float horizontal, float vertical);
+ void Offset(const Vector2dF& distance) { Offset(distance.x(), distance.y()); }
+ const RRectF& operator+=(const gfx::Vector2dF& offset);
+ const RRectF& operator-=(const gfx::Vector2dF& offset);
+
+ std::string ToString() const;
+
+ // Insets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may
+ // be positive, negative, or zero. If either corner radius is zero, the corner
+ // has no curvature and is unchanged. Otherwise, if adjusted radius becomes
+ // negative, the radius is pinned to zero.
+ void Inset(float val) { skrrect_.inset(val, val); }
+ void Inset(float dx, float dy) { skrrect_.inset(dx, dy); }
+ // Outsets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may
+ // be positive, negative, or zero. If either corner radius is zero, the corner
+ // has no curvature and is unchanged. Otherwise, if adjusted radius becomes
+ // negative, the radius is pinned to zero.
+ void Outset(float val) { skrrect_.outset(val, val); }
+ void Outset(float dx, float dy) { skrrect_.outset(dx, dy); }
+
+ explicit operator SkRRect() const { return skrrect_; }
+
+ private:
+ void GetAllRadii(SkVector radii[4]) const;
+
+ SkRRect skrrect_;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const RRectF& rect) {
+ return os << rect.ToString();
+}
+
+inline bool operator==(const RRectF& a, const RRectF& b) {
+ return a.Equals(b);
+}
+
+inline bool operator!=(const RRectF& a, const RRectF& b) {
+ return !(a == b);
+}
+
+inline RRectF operator+(const RRectF& a, const gfx::Vector2dF& b) {
+ RRectF result = a;
+ result += b;
+ return result;
+}
+
+inline RRectF operator-(const RRectF& a, const Vector2dF& b) {
+ RRectF result = a;
+ result -= b;
+ return result;
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_RRECT_F_H_
diff --git a/chromium/ui/gfx/rrect_f_unittest.cc b/chromium/ui/gfx/rrect_f_unittest.cc
new file mode 100644
index 00000000000..5c31570fcc1
--- /dev/null
+++ b/chromium/ui/gfx/rrect_f_unittest.cc
@@ -0,0 +1,232 @@
+// 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/rrect_f.h"
+#include "base/stl_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gfx {
+
+TEST(RRectFTest, IsEmpty) {
+ EXPECT_TRUE(RRectF().IsEmpty());
+ EXPECT_TRUE(RRectF(0, 0, 0, 0, 0).IsEmpty());
+ EXPECT_TRUE(RRectF(0, 0, 10, 0, 0).IsEmpty());
+ EXPECT_TRUE(RRectF(0, 0, 0, 10, 0).IsEmpty());
+ EXPECT_TRUE(RRectF(0, 0, 0, 10, 10).IsEmpty());
+ EXPECT_FALSE(RRectF(0, 0, 10, 10, 0).IsEmpty());
+}
+
+TEST(RRectFTest, Equals) {
+ ASSERT_TRUE(RRectF(0, 0, 0, 0, 0, 0) == RRectF(0, 0, 0, 0, 0, 0));
+ ASSERT_TRUE(RRectF(1, 2, 3, 4, 5, 6) == RRectF(1, 2, 3, 4, 5, 6));
+ ASSERT_TRUE(RRectF(1, 2, 3, 4, 5, 5) == RRectF(1, 2, 3, 4, 5));
+ ASSERT_TRUE(RRectF(0, 0, 2, 3, 0, 0) == RRectF(0, 0, 2, 3, 0, 1));
+ ASSERT_TRUE(RRectF(0, 0, 2, 3, 0, 0) == RRectF(0, 0, 2, 3, 1, 0));
+
+ ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(1, 20, 30, 40, 7, 8));
+ ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 2, 30, 40, 7, 8));
+ ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 20, 3, 40, 7, 8));
+ ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 20, 30, 4, 7, 8));
+ ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 20, 30, 40, 5, 8));
+ ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 20, 30, 40, 7, 6));
+}
+
+TEST(RRectFTest, PlusMinusOffset) {
+ const RRectF a(40, 50, 60, 70, 5);
+ gfx::Vector2d offset(23, 34);
+ RRectF correct(63, 84, 60, 70, 5);
+ RRectF b = a + offset;
+ ASSERT_EQ(b, correct);
+ b = a;
+ b.Offset(offset);
+ ASSERT_EQ(b, correct);
+
+ correct = RRectF(17, 16, 60, 70, 5);
+ b = a - offset;
+ ASSERT_EQ(b, correct);
+ b = a;
+ b.Offset(-offset);
+ ASSERT_EQ(b, correct);
+}
+
+TEST(RRectFTest, RRectTypes) {
+ RRectF a(40, 50, 0, 70, 0);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kEmpty);
+ EXPECT_TRUE(a.IsEmpty());
+ a = RRectF(40, 50, 60, 70, 0);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kRect);
+ a = RRectF(40, 50, 60, 70, 5);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kSingle);
+ a = RRectF(40, 50, 60, 70, 5, 5);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kSingle);
+ a = RRectF(40, 50, 60, 70, 6, 3);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kSimple);
+ a = RRectF(40, 50, 60, 70, 30, 3);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kSimple);
+ a = RRectF(40, 50, 60, 70, 30, 35);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kOval);
+ a.SetCornerRadii(RRectF::Corner::kLowerRight, gfx::Vector2dF(7, 8));
+ EXPECT_EQ(a.GetType(), RRectF::Type::kComplex);
+
+ // When one radius is larger than half its dimension, both radii are scaled
+ // down proportionately.
+ a = RRectF(40, 50, 60, 70, 30, 70);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kSimple);
+ EXPECT_EQ(a, RRectF(40, 50, 60, 70, 15, 35));
+ // If they stay equal to half the radius, it stays oval.
+ a = RRectF(40, 50, 60, 70, 120, 140);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kOval);
+}
+
+void CheckRadii(RRectF val,
+ float ulx,
+ float uly,
+ float urx,
+ float ury,
+ float lrx,
+ float lry,
+ float llx,
+ float lly) {
+ EXPECT_EQ(val.GetCornerRadii(RRectF::Corner::kUpperLeft),
+ gfx::Vector2dF(ulx, uly));
+ EXPECT_EQ(val.GetCornerRadii(RRectF::Corner::kUpperRight),
+ gfx::Vector2dF(urx, ury));
+ EXPECT_EQ(val.GetCornerRadii(RRectF::Corner::kLowerRight),
+ gfx::Vector2dF(lrx, lry));
+ EXPECT_EQ(val.GetCornerRadii(RRectF::Corner::kLowerLeft),
+ gfx::Vector2dF(llx, lly));
+}
+
+TEST(RRectFTest, RRectRadii) {
+ RRectF a(40, 50, 60, 70, 0);
+ CheckRadii(a, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ a.SetCornerRadii(RRectF::Corner::kUpperLeft, gfx::Vector2dF(1, 2));
+ CheckRadii(a, 1, 2, 0, 0, 0, 0, 0, 0);
+
+ a.SetCornerRadii(RRectF::Corner::kUpperRight, gfx::Vector2dF(3, 4));
+ CheckRadii(a, 1, 2, 3, 4, 0, 0, 0, 0);
+
+ a.SetCornerRadii(RRectF::Corner::kLowerRight, gfx::Vector2dF(5, 6));
+ CheckRadii(a, 1, 2, 3, 4, 5, 6, 0, 0);
+
+ a.SetCornerRadii(RRectF::Corner::kLowerLeft, gfx::Vector2dF(7, 8));
+ CheckRadii(a, 1, 2, 3, 4, 5, 6, 7, 8);
+}
+
+TEST(RRectFTest, FromRectF) {
+ // Check that explicit conversion from float rect works.
+ RectF a(40, 50, 60, 70);
+ RRectF b(40, 50, 60, 70, 0);
+ RRectF c = RRectF(a);
+ EXPECT_EQ(b, c);
+}
+
+TEST(RRectFTest, FromSkRRect) {
+ // Check that explicit conversion from SkRRect works.
+ SkRRect a = SkRRect::MakeRectXY(SkRect::MakeXYWH(40, 50, 60, 70), 15, 25);
+ RRectF b(40, 50, 60, 70, 15, 25);
+ RRectF c = RRectF(a);
+ EXPECT_EQ(b, c);
+
+ // Try with single radius constructor.
+ a = SkRRect::MakeRectXY(SkRect::MakeXYWH(40, 50, 60, 70), 15, 15);
+ b = RRectF(40, 50, 60, 70, 15);
+ c = RRectF(a);
+ EXPECT_EQ(b, c);
+}
+
+TEST(RRectFTest, ToString) {
+ RRectF a(40, 50, 60, 70, 0);
+ EXPECT_EQ(a.ToString(), "40.000,50.000 60.000x70.000, rectangular");
+ a = RRectF(40, 50, 60, 70, 15);
+ EXPECT_EQ(a.ToString(), "40.000,50.000 60.000x70.000, radius 15.000");
+ a = RRectF(40, 50, 60, 70, 15, 25);
+ EXPECT_EQ(a.ToString(),
+ "40.000,50.000 60.000x70.000, x_rad 15.000, y_rad 25.000");
+ a.SetCornerRadii(RRectF::Corner::kLowerRight, gfx::Vector2dF(7, 8));
+ EXPECT_EQ(a.ToString(),
+ "40.000,50.000 60.000x70.000, [15.000 25.000] "
+ "[15.000 25.000] [7.000 8.000] [15.000 25.000]");
+}
+
+TEST(RRectFTest, Sizes) {
+ RRectF a(40, 50, 60, 70, 5, 6);
+ EXPECT_EQ(a.rect().x(), 40);
+ EXPECT_EQ(a.rect().y(), 50);
+ EXPECT_EQ(a.rect().width(), 60);
+ EXPECT_EQ(a.rect().height(), 70);
+ EXPECT_EQ(a.GetSimpleRadii().x(), 5);
+ EXPECT_EQ(a.GetSimpleRadii().y(), 6);
+ a = RRectF(40, 50, 60, 70, 5, 5);
+ EXPECT_EQ(a.GetSimpleRadius(), 5);
+ a.Clear();
+ EXPECT_TRUE(a.IsEmpty());
+ // Make sure ovals can still get simple radii
+ a = RRectF(40, 50, 60, 70, 30, 35);
+ EXPECT_EQ(a.GetType(), RRectF::Type::kOval);
+ EXPECT_EQ(a.GetSimpleRadii().x(), 30);
+ EXPECT_EQ(a.GetSimpleRadii().y(), 35);
+}
+
+TEST(RRectFTest, Contains) {
+ RRectF a(40, 50, 60, 70, 5, 6);
+ RectF b(50, 60, 5, 6);
+ EXPECT_TRUE(a.Contains(b));
+ b = RectF(40, 50, 5, 6); // Right on the border
+ EXPECT_FALSE(a.Contains(b));
+ b = RectF(95, 114, 5, 6); // Right on the border
+ EXPECT_FALSE(a.Contains(b));
+ b = RectF(40, 50, 60, 70);
+ EXPECT_FALSE(a.Contains(b));
+}
+
+TEST(RRectFTest, Scale) {
+ // Note that SKRRect (the backing for RRectF) does not support scaling by NaN,
+ // scaling out of numerical bounds, or scaling to zero. So this test doesn't
+ // exercise those.
+ static const struct Test {
+ float x1; // source
+ float y1;
+ float w1;
+ float h1;
+ float r1;
+
+ float scale;
+ float x2; // target
+ float y2;
+ float w2;
+ float h2;
+ float r2;
+ } tests[] = {
+ {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.5f, 4.5f, 6.0f, 7.5f, 9.0f, 1.5f},
+ {3.0f, 4.0f, 5.0f, 6.0f, 0.0f, 1.5f, 4.5f, 6.0f, 7.5f, 9.0f, 0.0f},
+ };
+
+ for (size_t i = 0; i < base::size(tests); ++i) {
+ RRectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1, tests[i].r1);
+ RRectF r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2, tests[i].r2);
+
+ r1.Scale(tests[i].scale);
+ EXPECT_TRUE((r1.GetType() == RRectF::Type::kRect) ||
+ (r1.GetType() == RRectF::Type::kSingle));
+ EXPECT_EQ(r1.rect().x(), r2.rect().x());
+ EXPECT_EQ(r1.rect().y(), r2.rect().y());
+ EXPECT_EQ(r1.rect().width(), r2.rect().width());
+ EXPECT_EQ(r1.rect().height(), r2.rect().height());
+ EXPECT_EQ(r1.GetSimpleRadius(), r2.GetSimpleRadius());
+ }
+}
+
+TEST(RRectFTest, InsetOutset) {
+ RRectF a(40, 50, 60, 70, 5);
+ RRectF b = a;
+ b.Inset(3);
+ ASSERT_EQ(b, RRectF(43, 53, 54, 64, 2));
+ b = a;
+ b.Outset(3);
+ ASSERT_EQ(b, RRectF(37, 47, 66, 76, 8));
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/sequential_id_generator.h b/chromium/ui/gfx/sequential_id_generator.h
index 40bda2e1ef0..c61fca6466f 100644
--- a/chromium/ui/gfx/sequential_id_generator.h
+++ b/chromium/ui/gfx/sequential_id_generator.h
@@ -8,8 +8,8 @@
#include <stdint.h>
#include <map>
+#include <unordered_map>
-#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "ui/gfx/gfx_export.h"
@@ -39,7 +39,7 @@ class GFX_EXPORT SequentialIDGenerator {
void ResetForTest();
private:
- typedef base::hash_map<uint32_t, uint32_t> IDMap;
+ typedef std::unordered_map<uint32_t, uint32_t> IDMap;
uint32_t GetNextAvailableID();
diff --git a/chromium/ui/gfx/shadow_value_unittest.cc b/chromium/ui/gfx/shadow_value_unittest.cc
index d93e0967bbf..4cc191c7355 100644
--- a/chromium/ui/gfx/shadow_value_unittest.cc
+++ b/chromium/ui/gfx/shadow_value_unittest.cc
@@ -4,7 +4,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/vector2d.h"
@@ -58,7 +58,7 @@ TEST(ShadowValueTest, GetMargin) {
},
};
- for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ for (size_t i = 0; i < base::size(kTestCases); ++i) {
Insets margin = ShadowValue::GetMargin(
ShadowValues(kTestCases[i].shadows,
kTestCases[i].shadows + kTestCases[i].shadow_count));
diff --git a/chromium/ui/gfx/skbitmap_operations.cc b/chromium/ui/gfx/skbitmap_operations.cc
index 25bd1816f8d..3c0161290e1 100644
--- a/chromium/ui/gfx/skbitmap_operations.cc
+++ b/chromium/ui/gfx/skbitmap_operations.cc
@@ -107,8 +107,8 @@ SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
uint32_t* dst_row = masked.getAddr32(0, y);
for (int x = 0; x < masked.width(); ++x) {
- unsigned alpha = SkGetPackedA32(alpha_row[x]);
- unsigned scale = SkAlpha255To256(alpha);
+ unsigned alpha32 = SkGetPackedA32(alpha_row[x]);
+ unsigned scale = SkAlpha255To256(alpha32);
dst_row[x] = SkAlphaMulQ(rgb_row[x], scale);
}
}
diff --git a/chromium/ui/gfx/skia_util.cc b/chromium/ui/gfx/skia_util.cc
index bcb5dde7b79..4379e76c584 100644
--- a/chromium/ui/gfx/skia_util.cc
+++ b/chromium/ui/gfx/skia_util.cc
@@ -157,37 +157,4 @@ float HarfBuzzUnitsToFloat(int value) {
return kFloatToHbRatio * value;
}
-#if BUILDFLAG(ENABLE_VULKAN)
-VkFormat SkColorTypeToVkFormat(SkColorType color_type) {
- switch (color_type) {
- case kUnknown_SkColorType:
- break;
- case kAlpha_8_SkColorType:
- return VK_FORMAT_R8_UNORM;
- case kRGB_565_SkColorType:
- return VK_FORMAT_R5G6B5_UNORM_PACK16;
- case kARGB_4444_SkColorType:
- return VK_FORMAT_B4G4R4A4_UNORM_PACK16;
- case kRGBA_8888_SkColorType:
- return VK_FORMAT_R8G8B8A8_UNORM; // or VK_FORMAT_R8G8B8A8_SRGB
- case kRGB_888x_SkColorType: // Skia doesn't support it yet.
- break;
- case kBGRA_8888_SkColorType:
- return VK_FORMAT_B8G8R8A8_UNORM; // or VK_FORMAT_B8G8R8A8_SRGB
- case kRGBA_1010102_SkColorType:
- return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
- case kGray_8_SkColorType:
- return VK_FORMAT_R8_UNORM;
- case kRGBA_F16_SkColorType:
- return VK_FORMAT_R16G16B16A16_SFLOAT;
- case kRGBA_F32_SkColorType:
- return VK_FORMAT_R32G32B32A32_SFLOAT;
- case kRGB_101010x_SkColorType: // Skia doesn't support it yet.
- break;
- }
- NOTREACHED();
- return VK_FORMAT_UNDEFINED;
-}
-#endif
-
} // namespace gfx
diff --git a/chromium/ui/gfx/skia_util.h b/chromium/ui/gfx/skia_util.h
index beea3bd99b1..b73ff46146e 100644
--- a/chromium/ui/gfx/skia_util.h
+++ b/chromium/ui/gfx/skia_util.h
@@ -8,18 +8,12 @@
#include <string>
#include <vector>
-#include "gpu/vulkan/buildflags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry_skia_export.h"
-#if BUILDFLAG(ENABLE_VULKAN)
-#include "third_party/skia/include/core/SkImageInfo.h"
-#include "third_party/vulkan/include/vulkan/vulkan.h"
-#endif
-
class SkBitmap;
class SkMatrix;
@@ -70,11 +64,6 @@ GEOMETRY_SKIA_EXPORT SkScalar HarfBuzzUnitsToSkiaScalar(int value);
// Converts an hb_position_t to a float.
GEOMETRY_SKIA_EXPORT float HarfBuzzUnitsToFloat(int value);
-#if BUILDFLAG(ENABLE_VULKAN)
-// Converts a Skia color type to a compitable VkFormat
-GEOMETRY_SKIA_EXPORT VkFormat SkColorTypeToVkFormat(SkColorType color_type);
-#endif
-
} // namespace gfx
#endif // UI_GFX_SKIA_UTIL_H_
diff --git a/chromium/ui/gfx/sys_color_change_listener.cc b/chromium/ui/gfx/sys_color_change_listener.cc
index 6780105bb7d..0c7c7580d76 100644
--- a/chromium/ui/gfx/sys_color_change_listener.cc
+++ b/chromium/ui/gfx/sys_color_change_listener.cc
@@ -21,16 +21,16 @@ bool g_is_inverted_color_scheme = false;
bool g_is_inverted_color_scheme_initialized = false;
void UpdateInvertedColorScheme() {
- const uint8_t foreground_luma =
- color_utils::GetLuma(color_utils::GetSysSkColor(COLOR_WINDOWTEXT));
- const uint8_t background_luma =
- color_utils::GetLuma(color_utils::GetSysSkColor(COLOR_WINDOW));
HIGHCONTRAST high_contrast = {0};
high_contrast.cbSize = sizeof(HIGHCONTRAST);
- g_is_inverted_color_scheme =
+ const bool is_high_contrast =
SystemParametersInfo(SPI_GETHIGHCONTRAST, 0, &high_contrast, 0) &&
- ((high_contrast.dwFlags & HCF_HIGHCONTRASTON) != 0) &&
- foreground_luma > background_luma;
+ ((high_contrast.dwFlags & HCF_HIGHCONTRASTON) != 0);
+ g_is_inverted_color_scheme =
+ is_high_contrast && (color_utils::GetRelativeLuminance(
+ color_utils::GetSysSkColor(COLOR_WINDOWTEXT)) >
+ color_utils::GetRelativeLuminance(
+ color_utils::GetSysSkColor(COLOR_WINDOW)));
g_is_inverted_color_scheme_initialized = true;
}
diff --git a/chromium/ui/gfx/text_constants.h b/chromium/ui/gfx/text_constants.h
index 0ca89b1f228..fb1bab1ae5d 100644
--- a/chromium/ui/gfx/text_constants.h
+++ b/chromium/ui/gfx/text_constants.h
@@ -78,11 +78,12 @@ enum DirectionalityMode {
// Text styles and adornments.
// TODO(msw): Merge with gfx::Font::FontStyle.
enum TextStyle {
- ITALIC = 0,
- STRIKE,
- UNDERLINE,
- HEAVY_UNDERLINE,
- NUM_TEXT_STYLES,
+ TEXT_STYLE_ITALIC = 0,
+ TEXT_STYLE_STRIKE,
+ TEXT_STYLE_UNDERLINE,
+ TEXT_STYLE_HEAVY_UNDERLINE,
+
+ TEXT_STYLE_COUNT,
};
// Text baseline offset types.
diff --git a/chromium/ui/gfx/text_elider.cc b/chromium/ui/gfx/text_elider.cc
index 24d91a6efd4..085fc3c852d 100644
--- a/chromium/ui/gfx/text_elider.cc
+++ b/chromium/ui/gfx/text_elider.cc
@@ -11,6 +11,7 @@
#include <stdint.h>
+#include <algorithm>
#include <memory>
#include <string>
#include <vector>
@@ -126,24 +127,36 @@ StringSlicer::StringSlicer(const base::string16& text,
base::string16 StringSlicer::CutString(size_t length,
bool insert_ellipsis) const {
- const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_
- : base::string16();
+ const base::string16 ellipsis_text =
+ insert_ellipsis ? ellipsis_ : base::string16();
- if (elide_at_beginning_)
+ // For visual consistency, when eliding at either end of the string, excess
+ // space should be trimmed from the text to return "Foo bar..." instead of
+ // "Foo bar ...".
+
+ if (elide_at_beginning_) {
return ellipsis_text +
- text_.substr(
- FindValidBoundaryBefore(text_, text_.length() - length));
+ text_.substr(FindValidBoundaryAfter(text_, text_.length() - length,
+ /* trim_whitespace */ true));
+ }
- if (!elide_in_middle_)
- return text_.substr(0, FindValidBoundaryBefore(text_, length)) +
+ if (!elide_in_middle_) {
+ return text_.substr(0, FindValidBoundaryBefore(
+ text_, length, /* trim_whitespace */ true)) +
ellipsis_text;
+ }
- // We put the extra character, if any, before the cut.
+ // Put the extra character, if any, before the cut.
+ // Extra space around the ellipses will *not* be trimmed for |elide_in_middle|
+ // mode (we can change this later). The reason is that when laying out a
+ // column of middle-trimmed lines of text (such as a list of paths), the
+ // desired appearance is to be fully justified and the elipses should more or
+ // less line up; eliminating space would make the text look more ragged.
const size_t half_length = length / 2;
- const size_t prefix_length =
- FindValidBoundaryBefore(text_, length - half_length);
- const size_t suffix_start =
- FindValidBoundaryAfter(text_, text_.length() - half_length);
+ const size_t prefix_length = FindValidBoundaryBefore(
+ text_, length - half_length, /* trim_whitespace */ false);
+ const size_t suffix_start = FindValidBoundaryAfter(
+ text_, text_.length() - half_length, /* trim_whitespace */ false);
return text_.substr(0, prefix_length) + ellipsis_text +
text_.substr(suffix_start);
}
@@ -294,8 +307,8 @@ bool ElideString(const base::string16& input,
input.substr(input.length() - 1));
break;
default: {
- int rstr_len = (max_len - 3) / 2;
- int lstr_len = rstr_len + ((max_len - 3) % 2);
+ size_t rstr_len = (max_len - 3) / 2;
+ size_t lstr_len = rstr_len + ((max_len - 3) % 2);
output->assign(input.substr(0, lstr_len) + ASCIIToUTF16("...") +
input.substr(input.length() - rstr_len));
break;
@@ -434,11 +447,11 @@ void RectangleString::AddWord(const base::string16& word) {
base::i18n::UTF16CharIterator chars(&word);
while (!chars.end()) {
// When boundary is hit, add as much as will fit on this line.
- if (current_col_ + (chars.char_pos() - char_start) >= max_cols_) {
+ if (current_col_ + (chars.char_offset() - char_start) >= max_cols_) {
Append(word.substr(array_start, chars.array_pos() - array_start));
NewLine(true);
array_start = chars.array_pos();
- char_start = chars.char_pos();
+ char_start = chars.char_offset();
}
chars.Advance();
}
@@ -638,9 +651,9 @@ void RectangleText::AddLine(const base::string16& line) {
if (lines_added) {
if (truncate) {
// Trim trailing whitespace from the line that was added.
- const int line = lines_->size() - lines_added;
- base::TrimWhitespace(lines_->at(line), base::TRIM_TRAILING,
- &lines_->at(line));
+ const size_t new_line = lines_->size() - lines_added;
+ base::TrimWhitespace(lines_->at(new_line), base::TRIM_TRAILING,
+ &lines_->at(new_line));
}
if (base::ContainsOnlyChars(word, base::kWhitespaceUTF16)) {
// Skip the first space if the previous line was carried over.
diff --git a/chromium/ui/gfx/text_elider_unittest.cc b/chromium/ui/gfx/text_elider_unittest.cc
index 43852b6afe8..dc53cfd8e06 100644
--- a/chromium/ui/gfx/text_elider_unittest.cc
+++ b/chromium/ui/gfx/text_elider_unittest.cc
@@ -13,9 +13,9 @@
#include "base/files/file_path.h"
#include "base/i18n/rtl.h"
-#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -43,6 +43,9 @@ struct Testcase {
struct FileTestcase {
const base::FilePath::StringType input;
const std::string output;
+ // If this value is specified, we will try to cut the path down to the render
+ // width of this string; if not specified, output will be used.
+ const std::string using_width_of = std::string();
};
struct UTF16Testcase {
@@ -104,7 +107,7 @@ TEST(TextEliderTest, ElideEmail) {
};
const FontList font_list;
- for (size_t i = 0; i < arraysize(testcases); ++i) {
+ for (size_t i = 0; i < base::size(testcases); ++i) {
const base::string16 expected_output = UTF8ToUTF16(testcases[i].output);
EXPECT_EQ(expected_output,
ElideText(UTF8ToUTF16(testcases[i].input), font_list,
@@ -127,10 +130,10 @@ TEST(TextEliderTest, ElideEmailMoreSpace) {
};
const FontList font_list;
- for (size_t i = 0; i < arraysize(test_width_factors); ++i) {
+ for (size_t i = 0; i < base::size(test_width_factors); ++i) {
const int test_width =
font_list.GetExpectedTextWidth(test_width_factors[i]);
- for (size_t j = 0; j < arraysize(test_emails); ++j) {
+ for (size_t j = 0; j < base::size(test_emails); ++j) {
// Extra space is available: the email should not be elided.
const base::string16 test_email = UTF8ToUTF16(test_emails[j]);
EXPECT_EQ(test_email,
@@ -145,49 +148,51 @@ TEST(TextEliderTest, TestFilenameEliding) {
base::FilePath::StringType().append(1, base::FilePath::kSeparators[0]);
FileTestcase testcases[] = {
- {FILE_PATH_LITERAL(""), ""},
- {FILE_PATH_LITERAL("."), "."},
- {FILE_PATH_LITERAL("filename.exe"), "filename.exe"},
- {FILE_PATH_LITERAL(".longext"), ".longext"},
- {FILE_PATH_LITERAL("pie"), "pie"},
- {FILE_PATH_LITERAL("c:") + kPathSeparator + FILE_PATH_LITERAL("path") +
- kPathSeparator + FILE_PATH_LITERAL("filename.pie"),
- "filename.pie"},
- {FILE_PATH_LITERAL("c:") + kPathSeparator + FILE_PATH_LITERAL("path") +
- kPathSeparator + FILE_PATH_LITERAL("longfilename.pie"),
- "long" + kEllipsisStr + ".pie"},
- {FILE_PATH_LITERAL("http://path.com/filename.pie"), "filename.pie"},
- {FILE_PATH_LITERAL("http://path.com/longfilename.pie"),
- "long" + kEllipsisStr + ".pie"},
- {FILE_PATH_LITERAL("piesmashingtacularpants"), "pie" + kEllipsisStr},
- {FILE_PATH_LITERAL(".piesmashingtacularpants"), ".pie" + kEllipsisStr},
- {FILE_PATH_LITERAL("cheese."), "cheese."},
- {FILE_PATH_LITERAL("file name.longext"),
- "file" + kEllipsisStr + ".longext"},
- {FILE_PATH_LITERAL("fil ename.longext"),
- "fil " + kEllipsisStr + ".longext"},
- {FILE_PATH_LITERAL("filename.longext"),
- "file" + kEllipsisStr + ".longext"},
- {FILE_PATH_LITERAL("filename.middleext.longext"),
- "filename.mid" + kEllipsisStr + ".longext"},
- {FILE_PATH_LITERAL("filename.superduperextremelylongext"),
- "filename.sup" + kEllipsisStr + "emelylongext"},
- {FILE_PATH_LITERAL("filenamereallylongtext.superduperextremelylongext"),
- "filenamereall" + kEllipsisStr + "emelylongext"},
- {FILE_PATH_LITERAL("file.name.really.long.text.superduperextremelylongext"),
- "file.name.re" + kEllipsisStr + "emelylongext"}
- };
+ {FILE_PATH_LITERAL(""), ""},
+ {FILE_PATH_LITERAL("."), "."},
+ {FILE_PATH_LITERAL("filename.exe"), "filename.exe"},
+ {FILE_PATH_LITERAL(".longext"), ".longext"},
+ {FILE_PATH_LITERAL("pie"), "pie"},
+ {FILE_PATH_LITERAL("c:") + kPathSeparator + FILE_PATH_LITERAL("path") +
+ kPathSeparator + FILE_PATH_LITERAL("filename.pie"),
+ "filename.pie"},
+ {FILE_PATH_LITERAL("c:") + kPathSeparator + FILE_PATH_LITERAL("path") +
+ kPathSeparator + FILE_PATH_LITERAL("longfilename.pie"),
+ "long" + kEllipsisStr + ".pie"},
+ {FILE_PATH_LITERAL("http://path.com/filename.pie"), "filename.pie"},
+ {FILE_PATH_LITERAL("http://path.com/longfilename.pie"),
+ "long" + kEllipsisStr + ".pie"},
+ {FILE_PATH_LITERAL("piesmashingtacularpants"), "pie" + kEllipsisStr},
+ {FILE_PATH_LITERAL(".piesmashingtacularpants"), ".pie" + kEllipsisStr},
+ {FILE_PATH_LITERAL("cheese."), "cheese."},
+ {FILE_PATH_LITERAL("file name.longext"),
+ "file" + kEllipsisStr + ".longext"},
+ {FILE_PATH_LITERAL("fil ename.longext"),
+ "fil" + kEllipsisStr + ".longext", "fil " + kEllipsisStr + ".longext"},
+ {FILE_PATH_LITERAL("filename.longext"),
+ "file" + kEllipsisStr + ".longext"},
+ {FILE_PATH_LITERAL("filename.middleext.longext"),
+ "filename.mid" + kEllipsisStr + ".longext"},
+ {FILE_PATH_LITERAL("filename.superduperextremelylongext"),
+ "filename.sup" + kEllipsisStr + "emelylongext"},
+ {FILE_PATH_LITERAL("filenamereallylongtext.superduperextremelylongext"),
+ "filenamereall" + kEllipsisStr + "emelylongext"},
+ {FILE_PATH_LITERAL(
+ "file.name.really.long.text.superduperextremelylongext"),
+ "file.name.re" + kEllipsisStr + "emelylongext"}};
static const FontList font_list;
- for (size_t i = 0; i < arraysize(testcases); ++i) {
+ for (size_t i = 0; i < base::size(testcases); ++i) {
base::FilePath filepath(testcases[i].input);
base::string16 expected = UTF8ToUTF16(testcases[i].output);
+ base::string16 using_width_of = UTF8ToUTF16(
+ testcases[i].using_width_of.empty() ? testcases[i].output
+ : testcases[i].using_width_of);
expected = base::i18n::GetDisplayStringInLTRDirectionality(expected);
EXPECT_EQ(expected,
- ElideFilename(
- filepath, font_list,
- GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list),
- Typesetter::DEFAULT));
+ ElideFilename(filepath, font_list,
+ GetStringWidthF(using_width_of, font_list),
+ Typesetter::DEFAULT));
}
}
@@ -207,7 +212,7 @@ TEST(TextEliderTest, ElideTextTruncate) {
{ "Tests", kTestWidth, "Test" },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
cases[i].width, TRUNCATE);
EXPECT_EQ(cases[i].output, UTF16ToUTF8(result));
@@ -233,7 +238,7 @@ TEST(TextEliderTest, ElideTextEllipsis) {
{ "Test", kTestWidth, "Test" },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
cases[i].width, ELIDE_TAIL);
EXPECT_EQ(cases[i].output, UTF16ToUTF8(result));
@@ -262,7 +267,7 @@ TEST(TextEliderTest, ElideTextEllipsisFront) {
{ "Test123", kEllipsis23Width, UTF8ToUTF16(kEllipsisStr + "23") },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
cases[i].width, ELIDE_HEAD);
EXPECT_EQ(cases[i].output, result);
@@ -357,7 +362,7 @@ TEST(TextEliderTest, ElideTextLongStrings) {
const FontList font_list;
float ellipsis_width = GetStringWidthF(kEllipsisStr, font_list);
- for (size_t i = 0; i < arraysize(testcases_end); ++i) {
+ for (size_t i = 0; i < base::size(testcases_end); ++i) {
// Compare sizes rather than actual contents because if the test fails,
// output is rather long.
EXPECT_EQ(testcases_end[i].output.size(),
@@ -382,7 +387,7 @@ TEST(TextEliderTest, ElideTextLongStrings) {
{ data_scheme + million_a, long_string_middle },
};
- for (size_t i = 0; i < arraysize(testcases_middle); ++i) {
+ for (size_t i = 0; i < base::size(testcases_middle); ++i) {
// Compare sizes rather than actual contents because if the test fails,
// output is rather long.
EXPECT_EQ(testcases_middle[i].output.size(),
@@ -404,7 +409,7 @@ TEST(TextEliderTest, ElideTextLongStrings) {
{ data_scheme + hundred_thousand_a, long_string_beginning },
{ data_scheme + million_a, long_string_beginning },
};
- for (size_t i = 0; i < arraysize(testcases_beginning); ++i) {
+ for (size_t i = 0; i < base::size(testcases_beginning); ++i) {
EXPECT_EQ(testcases_beginning[i].output.size(),
ElideText(
testcases_beginning[i].input, font_list,
@@ -445,6 +450,43 @@ TEST(TextEliderTest, StringSlicerBasicTest) {
slicer_mid.CutString(5, true));
}
+TEST(TextEliderTest, StringSlicerWhitespace) {
+ // Must store strings in variables (StringSlicer retains a reference to them).
+ base::string16 text(UTF8ToUTF16("Hello, world!"));
+ base::string16 ellipsis(kEllipsisUTF16);
+
+ // Eliding the end of a string should result in whitespace being removed
+ // before the ellipsis.
+ StringSlicer slicer_end(text, ellipsis, false, false);
+ EXPECT_EQ(UTF8ToUTF16("Hello,") + kEllipsisUTF16,
+ slicer_end.CutString(6, true));
+ EXPECT_EQ(UTF8ToUTF16("Hello,") + kEllipsisUTF16,
+ slicer_end.CutString(7, true));
+ EXPECT_EQ(UTF8ToUTF16("Hello, w") + kEllipsisUTF16,
+ slicer_end.CutString(8, true));
+
+ // Eliding the start of a string should result in whitespace being removed
+ // after the ellipsis.
+ StringSlicer slicer_begin(text, ellipsis, false, true);
+ EXPECT_EQ(kEllipsisUTF16 + UTF8ToUTF16("world!"),
+ slicer_begin.CutString(6, true));
+ EXPECT_EQ(kEllipsisUTF16 + UTF8ToUTF16("world!"),
+ slicer_begin.CutString(7, true));
+ EXPECT_EQ(kEllipsisUTF16 + UTF8ToUTF16(", world!"),
+ slicer_begin.CutString(8, true));
+
+ // Eliding the middle of a string should *NOT* result in whitespace being
+ // removed around the ellipsis.
+ StringSlicer slicer_mid(text, ellipsis, true, false);
+ text = UTF8ToUTF16("Hey world!");
+ EXPECT_EQ(UTF8ToUTF16("Hey") + kEllipsisUTF16 + UTF8ToUTF16("ld!"),
+ slicer_mid.CutString(6, true));
+ EXPECT_EQ(UTF8ToUTF16("Hey ") + kEllipsisUTF16 + UTF8ToUTF16("ld!"),
+ slicer_mid.CutString(7, true));
+ EXPECT_EQ(UTF8ToUTF16("Hey ") + kEllipsisUTF16 + UTF8ToUTF16("rld!"),
+ slicer_mid.CutString(8, true));
+}
+
TEST(TextEliderTest, StringSlicerSurrogate) {
// The below is 'MUSICAL SYMBOL G CLEF' (U+1D11E), which is represented in
// UTF-16 as two code units forming a surrogate pair: 0xD834 0xDD1E.
@@ -458,9 +500,9 @@ TEST(TextEliderTest, StringSlicerSurrogate) {
EXPECT_EQ(UTF8ToUTF16("abc") + kEllipsisUTF16, slicer.CutString(4, true));
EXPECT_EQ(text + kEllipsisUTF16, slicer.CutString(text.length(), true));
- // Cut surrogate on the left. Should round left and include the surrogate.
+ // Cut surrogate on the left. Should round right and exclude the surrogate.
StringSlicer slicer_begin(text, ellipsis, false, true);
- EXPECT_EQ(base::string16(kEllipsisUTF16) + kSurrogate + UTF8ToUTF16("xyz"),
+ EXPECT_EQ(base::string16(kEllipsisUTF16) + UTF8ToUTF16("xyz"),
slicer_begin.CutString(4, true));
// Cut surrogate in the middle. Should round right and exclude the surrogate.
@@ -493,18 +535,20 @@ TEST(TextEliderTest, StringSlicerCombining) {
// Attempt to cut the string for all lengths. When a combining sequence is
// cut, it should always round left and exclude the combining sequence.
+ // Whitespace is also cut adjacent to the ellipsis.
+
// First sequence:
EXPECT_EQ(base::string16(kEllipsisUTF16), slicer.CutString(0, true));
EXPECT_EQ(base::string16(kEllipsisUTF16), slicer.CutString(1, true));
EXPECT_EQ(base::string16(kEllipsisUTF16), slicer.CutString(2, true));
EXPECT_EQ(text.substr(0, 3) + kEllipsisUTF16, slicer.CutString(3, true));
// Second sequence:
- EXPECT_EQ(text.substr(0, 4) + kEllipsisUTF16, slicer.CutString(4, true));
- EXPECT_EQ(text.substr(0, 4) + kEllipsisUTF16, slicer.CutString(5, true));
+ EXPECT_EQ(text.substr(0, 3) + kEllipsisUTF16, slicer.CutString(4, true));
+ EXPECT_EQ(text.substr(0, 3) + kEllipsisUTF16, slicer.CutString(5, true));
EXPECT_EQ(text.substr(0, 6) + kEllipsisUTF16, slicer.CutString(6, true));
// Third sequence:
- EXPECT_EQ(text.substr(0, 7) + kEllipsisUTF16, slicer.CutString(7, true));
- EXPECT_EQ(text.substr(0, 7) + kEllipsisUTF16, slicer.CutString(8, true));
+ EXPECT_EQ(text.substr(0, 6) + kEllipsisUTF16, slicer.CutString(7, true));
+ EXPECT_EQ(text.substr(0, 6) + kEllipsisUTF16, slicer.CutString(8, true));
EXPECT_EQ(text + kEllipsisUTF16, slicer.CutString(9, true));
// Cut string in the middle, splitting the second sequence in half. Should
@@ -565,7 +609,7 @@ TEST(TextEliderTest, ElideString) {
{ "Hello, my name is Tom", 10, true, "Hell...Tom" },
{ "Hello, my name is Tom", 100, false, "Hello, my name is Tom" }
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
base::string16 output;
EXPECT_EQ(cases[i].result,
ElideString(UTF8ToUTF16(cases[i].input),
@@ -613,7 +657,7 @@ TEST(TextEliderTest, ElideRectangleText) {
{ "Te Te Test", test_width, 3 * line_height, false, "Te|Te|Test" },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
std::vector<base::string16> lines;
EXPECT_EQ(cases[i].truncated_y ? INSUFFICIENT_SPACE_VERTICAL : 0,
ElideRectangleText(UTF8ToUTF16(cases[i].input),
@@ -705,7 +749,7 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) {
{ "Test. Test", test_width, line_height * 3, true, false, "Test|.|Test" },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
std::vector<base::string16> lines;
const WordWrapBehavior wrap_behavior =
(cases[i].wrap_words ? WRAP_LONG_WORDS : TRUNCATE_LONG_WORDS);
@@ -771,7 +815,7 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) {
{ "TestTestTestT", test_width, WRAP_LONG_WORDS, false, "Test|Test|Test|T" },
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
std::vector<base::string16> lines;
EXPECT_EQ(
cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0,
@@ -904,7 +948,7 @@ TEST(TextEliderTest, ElideRectangleString) {
{ "Hi, my name is Tom", 1, 40, false, "Hi, my name is Tom" },
};
base::string16 output;
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
EXPECT_EQ(cases[i].result,
ElideRectangleString(UTF8ToUTF16(cases[i].input),
cases[i].max_rows, cases[i].max_cols,
@@ -986,7 +1030,7 @@ TEST(TextEliderTest, ElideRectangleStringNotStrict) {
{ "Hi, my name_is Dick", 1, 40, false, "Hi, my name_is Dick" },
};
base::string16 output;
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
EXPECT_EQ(cases[i].result,
ElideRectangleString(UTF8ToUTF16(cases[i].input),
cases[i].max_rows, cases[i].max_cols,
diff --git a/chromium/ui/gfx/text_utils.cc b/chromium/ui/gfx/text_utils.cc
index d462b678c9e..f78ae639d2a 100644
--- a/chromium/ui/gfx/text_utils.cc
+++ b/chromium/ui/gfx/text_utils.cc
@@ -15,22 +15,25 @@
namespace gfx {
+using base::i18n::UTF16CharIterator;
+
namespace {
-// Returns true if the code point |c| is a combining mark character in Unicode.
-bool CharIsMark(UChar32 c) {
- int8_t char_type = u_charType(c);
+// Returns true if the specified character must be elided from a string.
+// Examples are combining marks and whitespace.
+bool IsCombiningMark(UChar32 c) {
+ const int8_t char_type = u_charType(c);
return char_type == U_NON_SPACING_MARK || char_type == U_ENCLOSING_MARK ||
char_type == U_COMBINING_SPACING_MARK;
}
-// Gets the code point of |str| at the given code unit position |index|. If
-// |index| is a surrogate code unit, returns the whole code point (unless the
-// code unit is unpaired, in which case it just returns the surrogate value).
-UChar32 GetCodePointAt(const base::string16& str, size_t index) {
- UChar32 c;
- U16_GET(str.data(), 0, index, str.size(), c);
- return c;
+bool IsSpace(UChar32 c) {
+ // Ignore NUL character.
+ if (!c)
+ return false;
+ const int8_t char_type = u_charType(c);
+ return char_type == U_SPACE_SEPARATOR || char_type == U_LINE_SEPARATOR ||
+ char_type == U_PARAGRAPH_SEPARATOR || char_type == U_CONTROL_CHAR;
}
} // namespace
@@ -42,7 +45,7 @@ base::string16 RemoveAcceleratorChar(const base::string16& s,
bool escaped = false;
ptrdiff_t last_char_pos = -1;
int last_char_span = 0;
- base::i18n::UTF16CharIterator chars(&s);
+ UTF16CharIterator chars(&s);
base::string16 accelerator_removed;
accelerator_removed.reserve(s.size());
@@ -73,40 +76,46 @@ base::string16 RemoveAcceleratorChar(const base::string16& s,
return accelerator_removed;
}
-size_t FindValidBoundaryBefore(const base::string16& text, size_t index) {
- size_t length = text.length();
- DCHECK_LE(index, length);
- if (index == length)
- return index;
-
- // If |index| straddles a combining character sequence, go back until we find
- // a base character.
- while (index > 0 && CharIsMark(GetCodePointAt(text, index)))
- --index;
+size_t FindValidBoundaryBefore(const base::string16& text,
+ size_t index,
+ bool trim_whitespace) {
+ UTF16CharIterator it = UTF16CharIterator::LowerBound(&text, index);
- // If |index| straddles a UTF-16 surrogate pair, go back.
- U16_SET_CP_START(text.data(), 0, index);
- return index;
-}
+ // First, move left until we're positioned on a code point that is not a
+ // combining mark.
+ while (!it.start() && IsCombiningMark(it.get()))
+ it.Rewind();
-size_t FindValidBoundaryAfter(const base::string16& text, size_t index) {
- DCHECK_LE(index, text.length());
- if (index == text.length())
- return index;
+ // Next, maybe trim whitespace to the left of the current position.
+ if (trim_whitespace) {
+ while (!it.start() && IsSpace(it.PreviousCodePoint()))
+ it.Rewind();
+ }
- int32_t text_index = base::checked_cast<int32_t>(index);
- int32_t text_length = base::checked_cast<int32_t>(text.length());
+ return it.array_pos();
+}
- // If |index| straddles a combining character sequence, go forward until we
- // find a base character.
- while (text_index < text_length &&
- CharIsMark(GetCodePointAt(text, text_index))) {
- ++text_index;
+size_t FindValidBoundaryAfter(const base::string16& text,
+ size_t index,
+ bool trim_whitespace) {
+ UTF16CharIterator it = UTF16CharIterator::UpperBound(&text, index);
+
+ // First, move right until we're positioned on a code point that is not a
+ // combining mark.
+ while (!it.end() && IsCombiningMark(it.get()))
+ it.Advance();
+
+ // Next, maybe trim space at the current position.
+ if (trim_whitespace) {
+ // A mark combining with a space is renderable, so we'll prevent
+ // trimming spaces with combining marks.
+ while (!it.end() && IsSpace(it.get()) &&
+ !IsCombiningMark(it.NextCodePoint())) {
+ it.Advance();
+ }
}
- // If |index| straddles a UTF-16 surrogate pair, go forward.
- U16_SET_CP_LIMIT(text.data(), 0, text_index, text_length);
- return static_cast<size_t>(text_index);
+ return it.array_pos();
}
HorizontalAlignment MaybeFlipForRTL(HorizontalAlignment alignment) {
diff --git a/chromium/ui/gfx/text_utils.h b/chromium/ui/gfx/text_utils.h
index 462d7690dd7..f2f5f792604 100644
--- a/chromium/ui/gfx/text_utils.h
+++ b/chromium/ui/gfx/text_utils.h
@@ -39,13 +39,15 @@ GFX_EXPORT float GetStringWidthF(const base::string16& text,
// Returns a valid cut boundary at or before |index|. The surrogate pair and
// combining characters should not be separated.
-GFX_EXPORT size_t
-FindValidBoundaryBefore(const base::string16& text, size_t index);
+GFX_EXPORT size_t FindValidBoundaryBefore(const base::string16& text,
+ size_t index,
+ bool trim_whitespace = false);
// Returns a valid cut boundary at or after |index|. The surrogate pair and
// combining characters should not be separated.
-GFX_EXPORT size_t
-FindValidBoundaryAfter(const base::string16& text, size_t index);
+GFX_EXPORT size_t FindValidBoundaryAfter(const base::string16& text,
+ size_t index,
+ bool trim_whitespace = false);
// If the UI layout is right-to-left, flip the alignment direction.
GFX_EXPORT HorizontalAlignment MaybeFlipForRTL(HorizontalAlignment alignment);
diff --git a/chromium/ui/gfx/text_utils_unittest.cc b/chromium/ui/gfx/text_utils_unittest.cc
index 7cf42c827ee..e3babfd40d3 100644
--- a/chromium/ui/gfx/text_utils_unittest.cc
+++ b/chromium/ui/gfx/text_utils_unittest.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -17,52 +17,13 @@ namespace {
const base::char16 kAcceleratorChar = '&';
-TEST(TextUtilsTest, RemoveAcceleratorChar) {
- struct TestData {
- const char* input;
- int accelerated_char_pos;
- int accelerated_char_span;
- const char* output;
- } cases[] = {
- { "", -1, 0, "" },
- { "&", -1, 0, "" },
- { "no accelerator", -1, 0, "no accelerator" },
- { "&one accelerator", 0, 1, "one accelerator" },
- { "one &accelerator", 4, 1, "one accelerator" },
- { "one_accelerator&", -1, 0, "one_accelerator" },
- { "&two &accelerators", 4, 1, "two accelerators" },
- { "two &accelerators&", 4, 1, "two accelerators" },
- { "two& &accelerators", 4, 1, "two accelerators" },
- { "&&escaping", -1, 0, "&escaping" },
- { "escap&&ing", -1, 0, "escap&ing" },
- { "escaping&&", -1, 0, "escaping&" },
- { "&mix&&ed", 0, 1, "mix&ed" },
- { "&&m&ix&&e&d&", 6, 1, "&mix&ed" },
- { "&&m&&ix&ed&&", 5, 1, "&m&ixed&" },
- { "&m&&ix&ed&&", 4, 1, "m&ixed&" },
- // U+1D49C MATHEMATICAL SCRIPT CAPITAL A, which occupies two |char16|'s.
- { "&\xF0\x9D\x92\x9C", 0, 2, "\xF0\x9D\x92\x9C" },
- { "Test&\xF0\x9D\x92\x9Cing", 4, 2, "Test\xF0\x9D\x92\x9Cing" },
- { "Test\xF0\x9D\x92\x9C&ing", 6, 1, "Test\xF0\x9D\x92\x9Cing" },
- { "Test&\xF0\x9D\x92\x9C&ing", 6, 1, "Test\xF0\x9D\x92\x9Cing" },
- { "Test&\xF0\x9D\x92\x9C&&ing", 4, 2, "Test\xF0\x9D\x92\x9C&ing" },
- { "Test&\xF0\x9D\x92\x9C&\xF0\x9D\x92\x9Cing", 6, 2,
- "Test\xF0\x9D\x92\x9C\xF0\x9D\x92\x9Cing" },
- };
-
- for (size_t i = 0; i < arraysize(cases); ++i) {
- int accelerated_char_pos;
- int accelerated_char_span;
- base::string16 result = RemoveAcceleratorChar(
- base::UTF8ToUTF16(cases[i].input),
- kAcceleratorChar,
- &accelerated_char_pos,
- &accelerated_char_span);
- EXPECT_EQ(result, base::UTF8ToUTF16(cases[i].output));
- EXPECT_EQ(accelerated_char_pos, cases[i].accelerated_char_pos);
- EXPECT_EQ(accelerated_char_span, cases[i].accelerated_char_span);
- }
-}
+struct RemoveAcceleratorCharData {
+ const char* input;
+ int accelerated_char_pos;
+ int accelerated_char_span;
+ const char* output;
+ const char* name;
+};
TEST(TextUtilsTest, GetStringWidth) {
FontList font_list;
@@ -75,5 +36,216 @@ TEST(TextUtilsTest, GetStringWidth) {
GetStringWidth(base::ASCIIToUTF16("ab"), font_list));
}
+class RemoveAcceleratorCharTest
+ : public testing::TestWithParam<RemoveAcceleratorCharData> {
+ public:
+ static const RemoveAcceleratorCharData kCases[];
+};
+
+const RemoveAcceleratorCharData RemoveAcceleratorCharTest::kCases[] = {
+ {"", -1, 0, "", "EmptyString"},
+ {"&", -1, 0, "", "AcceleratorCharOnly"},
+ {"no accelerator", -1, 0, "no accelerator", "NoAccelerator"},
+ {"&one accelerator", 0, 1, "one accelerator", "OneAccelerator_Start"},
+ {"one &accelerator", 4, 1, "one accelerator", "OneAccelerator_Middle"},
+ {"one_accelerator&", -1, 0, "one_accelerator", "OneAccelerator_End"},
+ {"&two &accelerators", 4, 1, "two accelerators",
+ "TwoAccelerators_OneAtStart"},
+ {"two &accelerators&", 4, 1, "two accelerators",
+ "TwoAccelerators_OneAtEnd"},
+ {"two& &accelerators", 4, 1, "two accelerators",
+ "TwoAccelerators_SpaceBetween"},
+ {"&&escaping", -1, 0, "&escaping", "Escape_Start"},
+ {"escap&&ing", -1, 0, "escap&ing", "Escape_Middle"},
+ {"escaping&&", -1, 0, "escaping&", "Escape_End"},
+ {"&mix&&ed", 0, 1, "mix&ed", "Mixed_EscapeAfterAccelerator"},
+ {"&&m&ix&&e&d&", 6, 1, "&mix&ed", "Mixed_MiddleAcceleratorSkipped"},
+ {"&&m&&ix&ed&&", 5, 1, "&m&ixed&", "Mixed_OneAccelerator"},
+ {"&m&&ix&ed&&", 4, 1, "m&ixed&", "Mixed_InitialAcceleratorSkipped"},
+ // U+1D49C MATHEMATICAL SCRIPT CAPITAL A, which occupies two |char16|'s.
+ {"&\U0001D49C", 0, 2, "\U0001D49C", "MultibyteAccelerator_Start"},
+ {"Test&\U0001D49Cing", 4, 2, "Test\U0001D49Cing",
+ "MultibyteAccelerator_Middle"},
+ {"Test\U0001D49C&ing", 6, 1, "Test\U0001D49Cing",
+ "OneAccelerator_AfterMultibyte"},
+ {"Test&\U0001D49C&ing", 6, 1, "Test\U0001D49Cing",
+ "MultibyteAccelerator_Skipped"},
+ {"Test&\U0001D49C&&ing", 4, 2, "Test\U0001D49C&ing",
+ "MultibyteAccelerator_EscapeAfter"},
+ {"Test&\U0001D49C&\U0001D49Cing", 6, 2, "Test\U0001D49C\U0001D49Cing",
+ "MultibyteAccelerator_AfterMultibyteAccelerator"},
+};
+
+INSTANTIATE_TEST_CASE_P(
+ ,
+ RemoveAcceleratorCharTest,
+ testing::ValuesIn(RemoveAcceleratorCharTest::kCases),
+ [](const testing::TestParamInfo<RemoveAcceleratorCharData>& param_info) {
+ return param_info.param.name;
+ });
+
+TEST_P(RemoveAcceleratorCharTest, RemoveAcceleratorChar) {
+ RemoveAcceleratorCharData data = GetParam();
+ int accelerated_char_pos;
+ int accelerated_char_span;
+ base::string16 result =
+ RemoveAcceleratorChar(base::UTF8ToUTF16(data.input), kAcceleratorChar,
+ &accelerated_char_pos, &accelerated_char_span);
+ EXPECT_EQ(result, base::UTF8ToUTF16(data.output));
+ EXPECT_EQ(accelerated_char_pos, data.accelerated_char_pos);
+ EXPECT_EQ(accelerated_char_span, data.accelerated_char_span);
+}
+
+struct FindValidBoundaryData {
+ const char16_t* input;
+ size_t index_in;
+ bool trim_whitespace;
+ size_t index_out;
+ const char* name;
+};
+
+class FindValidBoundaryBeforeTest
+ : public testing::TestWithParam<FindValidBoundaryData> {
+ public:
+ static const FindValidBoundaryData kCases[];
+};
+
+const FindValidBoundaryData FindValidBoundaryBeforeTest::kCases[] = {
+ {u"", 0, false, 0, "Empty"},
+ {u"word", 0, false, 0, "StartOfString"},
+ {u"word", 4, false, 4, "EndOfString"},
+ {u"word", 2, false, 2, "MiddleOfString_OnValidCharacter"},
+ {u"w𐐷d", 2, false, 1, "MiddleOfString_OnSurrogatePair"},
+ {u"w𐐷d", 1, false, 1, "MiddleOfString_BeforeSurrogatePair"},
+ {u"w𐐷d", 3, false, 3, "MiddleOfString_AfterSurrogatePair"},
+ {u"wo d", 3, false, 3, "MiddleOfString_OnSpace_NoTrim"},
+ {u"wo d", 3, true, 2, "MiddleOfString_OnSpace_Trim"},
+ {u"wo d", 2, false, 2, "MiddleOfString_LeftOfSpace_NoTrim"},
+ {u"wo d", 2, true, 2, "MiddleOfString_LeftOfSpace_Trim"},
+ {u"wo\td", 3, false, 3, "MiddleOfString_OnTab_NoTrim"},
+ {u"wo\td", 3, true, 2, "MiddleOfString_OnTab_Trim"},
+ {u"w d", 3, false, 3, "MiddleOfString_MultipleWhitespace_NoTrim"},
+ {u"w d", 3, true, 1, "MiddleOfString_MultipleWhitespace_Trim"},
+ {u"w d", 2, false, 2, "MiddleOfString_MiddleOfWhitespace_NoTrim"},
+ {u"w d", 2, true, 1, "MiddleOfString_MiddleOfWhitespace_Trim"},
+ {u"w ", 3, false, 3, "EndOfString_Whitespace_NoTrim"},
+ {u"w ", 3, true, 1, "EndOfString_Whitespace_Trim"},
+ {u" d", 2, false, 2, "MiddleOfString_Whitespace_NoTrim"},
+ {u" d", 2, true, 0, "MiddleOfString_Whitespace_Trim"},
+ // COMBINING GRAVE ACCENT (U+0300)
+ {u"wo\u0300d", 2, false, 1, "MiddleOfString_OnCombiningMark"},
+ {u"wo\u0300d", 1, false, 1, "MiddleOfString_BeforeCombiningMark"},
+ {u"wo\u0300d", 3, false, 3, "MiddleOfString_AfterCombiningMark"},
+ {u"w o\u0300d", 3, true, 1, "MiddleOfString_SpaceAndCombinginMark_Trim"},
+ {u"wo\u0300 d", 3, true, 3, "MiddleOfString_CombiningMarkAndSpace_Trim"},
+ {u"w \u0300d", 3, true, 3,
+ "MiddleOfString_AfterSpaceWithCombiningMark_Trim"},
+ {u"w \u0300d", 2, true, 1, "MiddleOfString_OnSpaceWithCombiningMark_Trim"},
+ {u"w \u0300 d", 4, true, 3,
+ "MiddleOfString_AfterSpaceAfterSpaceWithCombiningMark_Trim"},
+ // MUSICAL SYMBOL G CLEF (U+1D11E) + MUSICAL SYMBOL COMBINING FLAG-1
+ // (U+1D16E)
+ {u"w\U0001D11E\U0001D16Ed", 1, false, 1,
+ "MiddleOfString_BeforeCombiningSurrogate"},
+ {u"w\U0001D11E\U0001D16Ed", 2, false, 1,
+ "MiddleOfString_OnCombiningSurrogate_Pos1"},
+ {u"w\U0001D11E\U0001D16Ed", 3, false, 1,
+ "MiddleOfString_OnCombiningSurrogate_Pos2"},
+ {u"w\U0001D11E\U0001D16Ed", 4, false, 1,
+ "MiddleOfString_OnCombiningSurrogate_Pos3"},
+ {u"w\U0001D11E\U0001D16Ed", 5, false, 5,
+ "MiddleOfString_AfterCombiningSurrogate"},
+};
+
+INSTANTIATE_TEST_CASE_P(
+ ,
+ FindValidBoundaryBeforeTest,
+ testing::ValuesIn(FindValidBoundaryBeforeTest::kCases),
+ [](const testing::TestParamInfo<FindValidBoundaryData>& param_info) {
+ return param_info.param.name;
+ });
+
+TEST_P(FindValidBoundaryBeforeTest, FindValidBoundaryBefore) {
+ FindValidBoundaryData data = GetParam();
+ const base::string16::const_pointer input =
+ reinterpret_cast<base::string16::const_pointer>(data.input);
+ DLOG(INFO) << input;
+ size_t result =
+ FindValidBoundaryBefore(input, data.index_in, data.trim_whitespace);
+ EXPECT_EQ(data.index_out, result);
+}
+
+class FindValidBoundaryAfterTest
+ : public testing::TestWithParam<FindValidBoundaryData> {
+ public:
+ static const FindValidBoundaryData kCases[];
+};
+
+const FindValidBoundaryData FindValidBoundaryAfterTest::kCases[] = {
+ {u"", 0, false, 0, "Empty"},
+ {u"word", 0, false, 0, "StartOfString"},
+ {u"word", 4, false, 4, "EndOfString"},
+ {u"word", 2, false, 2, "MiddleOfString_OnValidCharacter"},
+ {u"w𐐷d", 2, false, 3, "MiddleOfString_OnSurrogatePair"},
+ {u"w𐐷d", 1, false, 1, "MiddleOfString_BeforeSurrogatePair"},
+ {u"w𐐷d", 3, false, 3, "MiddleOfString_AfterSurrogatePair"},
+ {u"wo d", 2, false, 2, "MiddleOfString_OnSpace_NoTrim"},
+ {u"wo d", 2, true, 3, "MiddleOfString_OnSpace_Trim"},
+ {u"wo d", 3, false, 3, "MiddleOfString_RightOfSpace_NoTrim"},
+ {u"wo d", 3, true, 3, "MiddleOfString_RightOfSpace_Trim"},
+ {u"wo\td", 2, false, 2, "MiddleOfString_OnTab_NoTrim"},
+ {u"wo\td", 2, true, 3, "MiddleOfString_OnTab_Trim"},
+ {u"w d", 1, false, 1, "MiddleOfString_MultipleWhitespace_NoTrim"},
+ {u"w d", 1, true, 3, "MiddleOfString_MultipleWhitespace_Trim"},
+ {u"w d", 2, false, 2, "MiddleOfString_MiddleOfWhitespace_NoTrim"},
+ {u"w d", 2, true, 3, "MiddleOfString_MiddleOfWhitespace_Trim"},
+ {u"w ", 1, false, 1, "MiddleOfString_Whitespace_NoTrim"},
+ {u"w ", 1, true, 3, "MiddleOfString_Whitespace_Trim"},
+ {u" d", 0, false, 0, "StartOfString_Whitespace_NoTrim"},
+ {u" d", 0, true, 2, "StartOfString_Whitespace_Trim"},
+ // COMBINING GRAVE ACCENT (U+0300)
+ {u"wo\u0300d", 2, false, 3, "MiddleOfString_OnCombiningMark"},
+ {u"wo\u0300d", 1, false, 1, "MiddleOfString_BeforeCombiningMark"},
+ {u"wo\u0300d", 3, false, 3, "MiddleOfString_AfterCombiningMark"},
+ {u"w o\u0300d", 1, true, 2, "MiddleOfString_SpaceAndCombinginMark_Trim"},
+ {u"wo\u0300 d", 1, true, 1,
+ "MiddleOfString_BeforeCombiningMarkAndSpace_Trim"},
+ {u"wo\u0300 d", 2, true, 4, "MiddleOfString_OnCombiningMarkAndSpace_Trim"},
+ {u"w \u0300d", 1, true, 1,
+ "MiddleOfString_BeforeSpaceWithCombiningMark_Trim"},
+ {u"w \u0300d", 2, true, 3, "MiddleOfString_OnSpaceWithCombiningMark_Trim"},
+ {u"w \u0300d", 1, true, 2,
+ "MiddleOfString_BeforeSpaceBeforeSpaceWithCombiningMark_Trim"},
+ // MUSICAL SYMBOL G CLEF (U+1D11E) + MUSICAL SYMBOL COMBINING FLAG-1
+ // (U+1D16E)
+ {u"w\U0001D11E\U0001D16Ed", 1, false, 1,
+ "MiddleOfString_BeforeCombiningSurrogate"},
+ {u"w\U0001D11E\U0001D16Ed", 2, false, 5,
+ "MiddleOfString_OnCombiningSurrogate_Pos1"},
+ {u"w\U0001D11E\U0001D16Ed", 3, false, 5,
+ "MiddleOfString_OnCombiningSurrogate_Pos2"},
+ {u"w\U0001D11E\U0001D16Ed", 4, false, 5,
+ "MiddleOfString_OnCombiningSurrogate_Pos3"},
+ {u"w\U0001D11E\U0001D16Ed", 5, false, 5,
+ "MiddleOfString_AfterCombiningSurrogate"},
+};
+
+INSTANTIATE_TEST_CASE_P(
+ ,
+ FindValidBoundaryAfterTest,
+ testing::ValuesIn(FindValidBoundaryAfterTest::kCases),
+ [](const testing::TestParamInfo<FindValidBoundaryData>& param_info) {
+ return param_info.param.name;
+ });
+
+TEST_P(FindValidBoundaryAfterTest, FindValidBoundaryAfter) {
+ FindValidBoundaryData data = GetParam();
+ const base::string16::const_pointer input =
+ reinterpret_cast<base::string16::const_pointer>(data.input);
+ size_t result =
+ FindValidBoundaryAfter(input, data.index_in, data.trim_whitespace);
+ EXPECT_EQ(data.index_out, result);
+}
+
} // namespace
} // namespace gfx
diff --git a/chromium/ui/gfx/transform_unittest.cc b/chromium/ui/gfx/transform_unittest.cc
index 6df8868b387..ee410a3c3cb 100644
--- a/chromium/ui/gfx/transform_unittest.cc
+++ b/chromium/ui/gfx/transform_unittest.cc
@@ -10,7 +10,7 @@
#include <ostream>
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/angle_conversions.h"
@@ -228,7 +228,7 @@ TEST(XFormTest, ConcatTranslate) {
};
Transform xform;
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
Transform translation;
translation.Translate(value.tx, value.ty);
@@ -257,7 +257,7 @@ TEST(XFormTest, ConcatScale) {
};
Transform xform;
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
Transform scale;
scale.Scale(value.scale, value.scale);
@@ -288,7 +288,7 @@ TEST(XFormTest, ConcatRotate) {
};
Transform xform;
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
Transform rotation;
rotation.Rotate(value.degrees);
@@ -317,7 +317,7 @@ TEST(XFormTest, SetTranslate) {
0, 0 }
};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
for (int k = 0; k < 3; ++k) {
Point3F p0, p1, p2;
@@ -364,7 +364,7 @@ TEST(XFormTest, SetScale) {
{ 1, std::numeric_limits<float>::quiet_NaN(), 0 },
};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
for (int k = 0; k < 3; ++k) {
Point3F p0, p1, p2;
@@ -417,7 +417,7 @@ TEST(XFormTest, SetRotate) {
{ 100, 0, 360.0f, 100, 0 }
};
- for (size_t i = 0; i < arraysize(set_rotate_cases); ++i) {
+ for (size_t i = 0; i < base::size(set_rotate_cases); ++i) {
const SetRotateCase& value = set_rotate_cases[i];
Point3F p0;
Point3F p1(value.x, value.y, 0);
@@ -451,7 +451,7 @@ TEST(XFormTest, ConcatTranslate2D) {
};
Transform xform;
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
Transform translation;
translation.Translate(value.tx, value.ty);
@@ -480,7 +480,7 @@ TEST(XFormTest, ConcatScale2D) {
};
Transform xform;
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
Transform scale;
scale.Scale(value.scale, value.scale);
@@ -511,7 +511,7 @@ TEST(XFormTest, ConcatRotate2D) {
};
Transform xform;
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
Transform rotation;
rotation.Rotate(value.degrees);
@@ -537,7 +537,7 @@ TEST(XFormTest, SetTranslate2D) {
{ 10, 20, 0.0f, 0.0f, 10, 20},
};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
for (int j = -1; j < 2; ++j) {
for (int k = 0; k < 3; ++k) {
@@ -589,7 +589,7 @@ TEST(XFormTest, SetScale2D) {
{ 0, 10.0f, 0},
};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
for (int j = -1; j < 2; ++j) {
for (int k = 0; k < 3; ++k) {
@@ -650,7 +650,7 @@ TEST(XFormTest, SetRotate2D) {
{ 100, 0, 360.0f, 100, 0}
};
- for (size_t i = 0; i < arraysize(set_rotate_cases); ++i) {
+ for (size_t i = 0; i < base::size(set_rotate_cases); ++i) {
const SetRotateCase& value = set_rotate_cases[i];
for (int j = 1; j >= -1; --j) {
float epsilon = 0.1f;
@@ -709,7 +709,7 @@ TEST(XFormTest, BlendRotate) {
Vector3dF(1, 1, 1)
};
Transform from;
- for (size_t index = 0; index < arraysize(axes); ++index) {
+ for (size_t index = 0; index < base::size(axes); ++index) {
for (int i = -5; i < 15; ++i) {
Transform to;
to.RotateAbout(axes[index], 90);
@@ -732,7 +732,7 @@ TEST(XFormTest, CanBlend180DegreeRotation) {
Vector3dF(1, 1, 1)
};
Transform from;
- for (size_t index = 0; index < arraysize(axes); ++index) {
+ for (size_t index = 0; index < base::size(axes); ++index) {
for (int i = -5; i < 15; ++i) {
Transform to;
to.RotateAbout(axes[index], 180.0);
@@ -2458,7 +2458,7 @@ TEST(XFormTest, Preserves2dAxisAlignment) {
};
Transform transform;
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
transform.MakeIdentity();
transform.matrix().set(0, 0, value.a);
@@ -2477,7 +2477,7 @@ TEST(XFormTest, Preserves2dAxisAlignment) {
// Try the same test cases again, but this time make sure that other matrix
// elements (except perspective) have entries, to test that they are ignored.
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
transform.MakeIdentity();
transform.matrix().set(0, 0, value.a);
@@ -2505,7 +2505,7 @@ TEST(XFormTest, Preserves2dAxisAlignment) {
// Try the same test cases again, but this time add perspective which is
// always assumed to not-preserve axis alignment.
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
const TestCase& value = test_cases[i];
transform.MakeIdentity();
transform.matrix().set(0, 0, value.a);
diff --git a/chromium/ui/gfx/typemaps.gni b/chromium/ui/gfx/typemaps.gni
index c4ea97d798c..d1347717cdb 100644
--- a/chromium/ui/gfx/typemaps.gni
+++ b/chromium/ui/gfx/typemaps.gni
@@ -13,6 +13,7 @@ typemaps = [
"//ui/gfx/mojo/gpu_fence_handle.typemap",
"//ui/gfx/mojo/overlay_transform.typemap",
"//ui/gfx/mojo/presentation_feedback.typemap",
+ "//ui/gfx/mojo/rrect_f.typemap",
"//ui/gfx/mojo/swap_result.typemap",
"//ui/gfx/mojo/selection_bound.typemap",
"//ui/gfx/mojo/transform.typemap",
diff --git a/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc b/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc
new file mode 100644
index 00000000000..2d2363477b2
--- /dev/null
+++ b/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.cc
@@ -0,0 +1,96 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/win/singleton_hwnd_hot_key_observer.h"
+
+#include "base/bind.h"
+#include "base/containers/flat_set.h"
+#include "base/memory/ptr_util.h"
+#include "base/no_destructor.h"
+#include "base/optional.h"
+#include "ui/gfx/win/singleton_hwnd.h"
+
+namespace gfx {
+
+namespace {
+
+base::flat_set<int>& GetUsedHotKeyIDs() {
+ static base::NoDestructor<base::flat_set<int>> used_hot_key_ids;
+ return *used_hot_key_ids;
+}
+
+base::Optional<int> GetAvailableHotKeyID() {
+ // Valid hot key IDs are in the range 0x0000 to 0xBFFF. See
+ // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-registerhotkey
+ for (int i = 0x0000; i < 0xBFFF; i++) {
+ if (!GetUsedHotKeyIDs().contains(i))
+ return i;
+ }
+ return base::nullopt;
+}
+
+void SetHotKeyIDUsed(int id) {
+ DCHECK(!GetUsedHotKeyIDs().contains(id));
+ GetUsedHotKeyIDs().insert(id);
+}
+
+void SetHotKeyIDAvailable(int id) {
+ DCHECK(GetUsedHotKeyIDs().contains(id));
+ GetUsedHotKeyIDs().erase(id);
+}
+
+} // anonymous namespace
+
+std::unique_ptr<SingletonHwndHotKeyObserver>
+SingletonHwndHotKeyObserver::Create(
+ const SingletonHwndObserver::WndProc& wnd_proc,
+ UINT key_code,
+ int modifiers) {
+ base::Optional<int> hot_key_id = GetAvailableHotKeyID();
+
+ // If there are no available hot key IDs, return null.
+ if (!hot_key_id.has_value())
+ return nullptr;
+
+ // If we fail to register the hot key, return null. Most likely reason for
+ // failure is that another application has already registered the hot key.
+ if (!RegisterHotKey(gfx::SingletonHwnd::GetInstance()->hwnd(), *hot_key_id,
+ modifiers, key_code)) {
+ return nullptr;
+ }
+
+ return base::WrapUnique(
+ new SingletonHwndHotKeyObserver(wnd_proc, *hot_key_id));
+}
+
+SingletonHwndHotKeyObserver::SingletonHwndHotKeyObserver(
+ const SingletonHwndObserver::WndProc& wnd_proc,
+ int hot_key_id)
+ : observer_(base::BindRepeating(&SingletonHwndHotKeyObserver::OnWndProc,
+ base::Unretained(this))),
+ wnd_proc_(wnd_proc),
+ hot_key_id_(hot_key_id) {
+ SetHotKeyIDUsed(hot_key_id);
+}
+
+SingletonHwndHotKeyObserver::~SingletonHwndHotKeyObserver() {
+ bool success = !!UnregisterHotKey(gfx::SingletonHwnd::GetInstance()->hwnd(),
+ hot_key_id_);
+ // This call should always succeed, as long as we pass in the right HWND and
+ // an id we've used to register before.
+ DCHECK(success);
+ SetHotKeyIDAvailable(hot_key_id_);
+}
+
+void SingletonHwndHotKeyObserver::OnWndProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ // Only propagate WM_HOTKEY messages for this particular hot key to the owner
+ // of this observer.
+ if (message == WM_HOTKEY && static_cast<int>(wparam) == hot_key_id_)
+ wnd_proc_.Run(hwnd, message, wparam, lparam);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.h b/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.h
new file mode 100644
index 00000000000..bbc992b6199
--- /dev/null
+++ b/chromium/ui/gfx/win/singleton_hwnd_hot_key_observer.h
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_WIN_SINGLETON_HWND_HOT_KEY_OBSERVER_H_
+#define UI_GFX_WIN_SINGLETON_HWND_HOT_KEY_OBSERVER_H_
+
+#include "base/win/windows_types.h"
+#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/win/singleton_hwnd_observer.h"
+
+namespace gfx {
+
+// We need to avoid duplicate hot key IDs for SingletonHwndObservers that call
+// RegisterHotKey for SingletonHwnd. This class properly handles getting a
+// unique hot key ID, registers the hotkey on construction, and unregisters the
+// hot key on destruction.
+//
+// This class should always be used instead of directly registering hot keys on
+// the SingletonHwnd with a SingletonHwndObserver in order to prevent duplicate
+// hot key IDs.
+class GFX_EXPORT SingletonHwndHotKeyObserver {
+ public:
+ // Registers a hot key with the given |key_code| and |modifiers| and returns
+ // a SingletonHwndHotKeyObserver if successful. Returns null if the hot key
+ // fails to register, which can happen if another application has already
+ // registered the hot key.
+ static std::unique_ptr<SingletonHwndHotKeyObserver> Create(
+ const SingletonHwndObserver::WndProc& wnd_proc,
+ UINT key_code,
+ int modifiers);
+ ~SingletonHwndHotKeyObserver();
+
+ private:
+ SingletonHwndHotKeyObserver(const SingletonHwndObserver::WndProc& wnd_proc,
+ int hot_key_id);
+
+ // Called by SingletonHwndObserver.
+ void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+
+ SingletonHwndObserver observer_;
+ SingletonHwndObserver::WndProc wnd_proc_;
+ const int hot_key_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SingletonHwndHotKeyObserver);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_WIN_SINGLETON_HWND_HOT_KEY_OBSERVER_H_
diff --git a/chromium/ui/gfx/win/singleton_hwnd_observer.h b/chromium/ui/gfx/win/singleton_hwnd_observer.h
index a1bd5244810..329a784c05a 100644
--- a/chromium/ui/gfx/win/singleton_hwnd_observer.h
+++ b/chromium/ui/gfx/win/singleton_hwnd_observer.h
@@ -17,6 +17,8 @@ class SingletonHwnd;
// Singleton lifetime management is tricky. This observer handles the correct
// cleanup if either the SingletonHwnd or forwarded object is destroyed first.
+// Note that if you want to register a hot key on the SingletonHwnd, you need to
+// use a SingletonHwndHotKeyObserver instead for each hot key.
class GFX_EXPORT SingletonHwndObserver {
public:
typedef base::Callback<void(HWND, UINT, WPARAM, LPARAM)> WndProc;
diff --git a/chromium/ui/gfx/x/x11_atom_cache.cc b/chromium/ui/gfx/x/x11_atom_cache.cc
index 3447421df8c..7405b880fcf 100644
--- a/chromium/ui/gfx/x/x11_atom_cache.cc
+++ b/chromium/ui/gfx/x/x11_atom_cache.cc
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/memory/singleton.h"
+#include "base/stl_util.h"
namespace {
@@ -228,7 +229,7 @@ constexpr const char* kAtomsToCache[] = {
"XdndTypeList",
};
-constexpr int kCacheCount = arraysize(kAtomsToCache);
+constexpr int kCacheCount = base::size(kAtomsToCache);
} // namespace
diff --git a/chromium/ui/gl/BUILD.gn b/chromium/ui/gl/BUILD.gn
index a3f8e6b24ca..77750dc5e9f 100644
--- a/chromium/ui/gl/BUILD.gn
+++ b/chromium/ui/gl/BUILD.gn
@@ -3,20 +3,24 @@
# found in the LICENSE file.
import("//build/buildflag_header.gni")
-import("//build/config/jumbo.gni")
import("//build/config/chrome_build.gni")
+import("//build/config/jumbo.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/ui.gni")
+import("//testing/test.gni")
import("//ui/gl/features.gni")
import("//ui/ozone/ozone.gni")
-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 == "arm64" || target_cpu == "mipsel" ||
- target_cpu == "mips64el")
+ target_cpu == "arm" || target_cpu == "arm64" ||
+ target_cpu == "mipsel" || target_cpu == "mips64el")
+
+ # Whether service side logging (actual calls into the GL driver) is enabled
+ # or not.
+ enable_gpu_service_logging = false
}
use_glx = use_x11 || ozone_platform_x11
@@ -26,8 +30,8 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-buildflag_header("gl_features") {
- header = "gl_features.h"
+buildflag_header("buildflags") {
+ header = "buildflags.h"
use_egl_on_mac = use_egl && is_mac
flags = [
"ENABLE_SWIFTSHADER=$enable_swiftshader",
@@ -143,6 +147,9 @@ jumbo_component("gl") {
configs += [ "//build/config:precompiled_headers" ]
defines = [ "GL_IMPLEMENTATION" ]
+ if (enable_gpu_service_logging) {
+ defines += [ "GPU_ENABLE_SERVICE_LOGGING" ]
+ }
include_dirs = [ "//third_party/mesa_headers" ]
@@ -151,7 +158,7 @@ jumbo_component("gl") {
public_configs = [ "//third_party/khronos:khronos_headers" ]
deps = [
- ":gl_features",
+ ":buildflags",
"//base/third_party/dynamic_annotations",
# ANGLE includes are used cross-platform.
@@ -323,8 +330,10 @@ jumbo_component("gl") {
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/mesa_headers",
- "//third_party/swiftshader",
]
+ if (enable_swiftshader) {
+ data_deps += [ "//third_party/swiftshader" ]
+ }
}
}
if (is_android) {
@@ -364,18 +373,20 @@ if (is_mac && use_egl) {
]
}
- copy("swiftshader_library_copy") {
- sources = [
- "$root_out_dir/libswiftshader_libEGL.dylib",
- "$root_out_dir/libswiftshader_libGLESv2.dylib",
- ]
- outputs = [
- "$root_out_dir/egl_intermediates/{{source_file_part}}",
- ]
- deps = [
- "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
- "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2",
- ]
+ if (enable_swiftshader) {
+ copy("swiftshader_library_copy") {
+ sources = [
+ "$root_out_dir/libswiftshader_libEGL.dylib",
+ "$root_out_dir/libswiftshader_libGLESv2.dylib",
+ ]
+ outputs = [
+ "$root_out_dir/egl_intermediates/{{source_file_part}}",
+ ]
+ deps = [
+ "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
+ "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2",
+ ]
+ }
}
}
@@ -459,6 +470,7 @@ source_set("run_all_unittests") {
deps += [
"//mojo/core/embedder",
"//services/service_manager/public/cpp/test:test_support",
+ "//services/ws/public/mojom:constants",
"//ui/ozone",
]
}
diff --git a/chromium/ui/gl/OWNERS b/chromium/ui/gl/OWNERS
index e3d6ad60e5d..de6fcfc9b70 100644
--- a/chromium/ui/gl/OWNERS
+++ b/chromium/ui/gl/OWNERS
@@ -1,5 +1,7 @@
+backer@chromium.org
kbr@chromium.org
piman@chromium.org
+zmo@chromium.org
per-file *gl_image*=reveman@chromium.org
per-file *gl_image*=dcastagna@chromium.org
per-file *_ozone*=alexst@chromium.org
diff --git a/chromium/ui/gl/android/android_surface_control_compat.cc b/chromium/ui/gl/android/android_surface_control_compat.cc
index ea826e06f3b..26c981c3e7e 100644
--- a/chromium/ui/gl/android/android_surface_control_compat.cc
+++ b/chromium/ui/gl/android/android_surface_control_compat.cc
@@ -12,41 +12,53 @@
extern "C" {
// ASurface
-using pASurfaceControl_CreateSurfaceForWindow =
- ASurface* (*)(ANativeWindow* parent, const char* name);
-using pASurfaceControl_CreateSurface = ASurface* (*)(ASurface* parent,
+using pASurfaceControl_createFromWindow =
+ ASurfaceControl* (*)(ANativeWindow* parent, const char* name);
+using pASurfaceControl_create = ASurfaceControl* (*)(ASurfaceControl* parent,
const char* name);
-using pASurfaceControl_DeleteSurface = void (*)(ASurface*);
+using pASurfaceControl_destroy = void (*)(ASurfaceControl*);
+
+// ASurfaceTransaction enums
+enum {
+ ASURFACE_TRANSACTION_TRANSPARENCY_TRANSPARENT = 0,
+ ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT = 1,
+ ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE = 2,
+};
+
+enum {
+ ASURFACE_TRANSACTION_VISIBILITY_HIDE = 0,
+ ASURFACE_TRANSACTION_VISIBILITY_SHOW = 1,
+};
// 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 =
+using pASurfaceTransaction_create = ASurfaceTransaction* (*)(void);
+using pASurfaceTransaction_delete = void (*)(ASurfaceTransaction*);
+using pASurfaceTransaction_apply = int64_t (*)(ASurfaceTransaction*);
+using pASurfaceTransaction_setOnComplete =
+ void (*)(ASurfaceTransaction*, void* ctx, ASurfaceTransaction_OnComplete);
+using pASurfaceTransaction_setVisibility = void (*)(ASurfaceTransaction*,
+ ASurfaceControl*,
+ int8_t visibility);
+using pASurfaceTransaction_setZOrder =
+ void (*)(ASurfaceTransaction* transaction, ASurfaceControl*, int32_t z);
+using pASurfaceTransaction_setBuffer =
void (*)(ASurfaceTransaction* transaction,
- ASurface*,
+ ASurfaceControl*,
AHardwareBuffer*,
int32_t fence_fd);
-using pASurfaceControl_TransactionSetCropRect =
+using pASurfaceTransaction_setGeometry =
void (*)(ASurfaceTransaction* transaction,
- ASurface* surface,
- const ARect& rect);
-using pASurfaceControl_TransactionSetDisplayFrame =
+ ASurfaceControl* surface,
+ const ARect& src,
+ const ARect& dst,
+ int32_t transform);
+using pASurfaceTransaction_setBufferTransparency =
void (*)(ASurfaceTransaction* transaction,
- ASurface* surface,
- const ARect& rect);
-using pASurfaceControl_TransactionSetBufferOpaque =
- void (*)(ASurfaceTransaction* transaction, ASurface* surface, bool opaque);
-using pASurfaceControl_TransactionSetDamageRegion =
+ ASurfaceControl* surface,
+ int8_t transparency);
+using pASurfaceTransaction_setDamageRegion =
void (*)(ASurfaceTransaction* transaction,
- ASurface* surface,
+ ASurfaceControl* surface,
const ARect rects[],
uint32_t count);
}
@@ -71,62 +83,76 @@ struct SurfaceControlMethods {
}
SurfaceControlMethods() {
- void* main_dl_handle = dlopen(nullptr, RTLD_NOW);
+ void* main_dl_handle = dlopen("libandroid.so", 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);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_createFromWindow);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_create);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_destroy);
+
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_create);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_delete);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_apply);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setOnComplete);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setVisibility);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setZOrder);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBuffer);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setGeometry);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBufferTransparency);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setDamageRegion);
}
~SurfaceControlMethods() = default;
bool supported = true;
// Surface methods.
- pASurfaceControl_CreateSurfaceForWindow
- ASurfaceControl_CreateSurfaceForWindowFn;
- pASurfaceControl_CreateSurface ASurfaceControl_CreateSurfaceFn;
- pASurfaceControl_DeleteSurface ASurfaceControl_DeleteSurfaceFn;
+ pASurfaceControl_createFromWindow ASurfaceControl_createFromWindowFn;
+ pASurfaceControl_create ASurfaceControl_createFn;
+ pASurfaceControl_destroy ASurfaceControl_destroyFn;
// 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;
+ pASurfaceTransaction_create ASurfaceTransaction_createFn;
+ pASurfaceTransaction_delete ASurfaceTransaction_deleteFn;
+ pASurfaceTransaction_apply ASurfaceTransaction_applyFn;
+ pASurfaceTransaction_setOnComplete ASurfaceTransaction_setOnCompleteFn;
+ pASurfaceTransaction_setVisibility ASurfaceTransaction_setVisibilityFn;
+ pASurfaceTransaction_setZOrder ASurfaceTransaction_setZOrderFn;
+ pASurfaceTransaction_setBuffer ASurfaceTransaction_setBufferFn;
+ pASurfaceTransaction_setGeometry ASurfaceTransaction_setGeometryFn;
+ pASurfaceTransaction_setBufferTransparency
+ ASurfaceTransaction_setBufferTransparencyFn;
+ pASurfaceTransaction_setDamageRegion ASurfaceTransaction_setDamageRegionFn;
};
ARect RectToARect(const gfx::Rect& rect) {
return ARect{rect.x(), rect.y(), rect.right(), rect.bottom()};
}
+
+int32_t OverlayTransformToWindowTransform(gfx::OverlayTransform transform) {
+ switch (transform) {
+ case gfx::OVERLAY_TRANSFORM_INVALID:
+ DCHECK(false) << "Invalid Transform";
+ return ANATIVEWINDOW_TRANSFORM_IDENTITY;
+ case gfx::OVERLAY_TRANSFORM_NONE:
+ return ANATIVEWINDOW_TRANSFORM_IDENTITY;
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL;
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
+ };
+ NOTREACHED();
+ return ANATIVEWINDOW_TRANSFORM_IDENTITY;
+}
};
// static
@@ -146,21 +172,20 @@ bool SurfaceControl::IsSupported() {
SurfaceControl::Surface::Surface() = default;
SurfaceControl::Surface::Surface(const Surface& parent, const char* name) {
- surface_ = SurfaceControlMethods::Get().ASurfaceControl_CreateSurfaceFn(
+ surface_ = SurfaceControlMethods::Get().ASurfaceControl_createFn(
parent.surface(), name);
DCHECK(surface_);
}
SurfaceControl::Surface::Surface(ANativeWindow* parent, const char* name) {
- surface_ =
- SurfaceControlMethods::Get().ASurfaceControl_CreateSurfaceForWindowFn(
- parent, name);
+ surface_ = SurfaceControlMethods::Get().ASurfaceControl_createFromWindowFn(
+ parent, name);
DCHECK(surface_);
}
SurfaceControl::Surface::~Surface() {
if (surface_)
- SurfaceControlMethods::Get().ASurfaceControl_DeleteSurfaceFn(surface_);
+ SurfaceControlMethods::Get().ASurfaceControl_destroyFn(surface_);
}
SurfaceControl::Surface::Surface(Surface&& other) {
@@ -170,7 +195,7 @@ SurfaceControl::Surface::Surface(Surface&& other) {
SurfaceControl::Surface& SurfaceControl::Surface::operator=(Surface&& other) {
if (surface_)
- SurfaceControlMethods::Get().ASurfaceControl_DeleteSurfaceFn(surface_);
+ SurfaceControlMethods::Get().ASurfaceControl_destroyFn(surface_);
surface_ = other.surface_;
other.surface_ = nullptr;
@@ -178,69 +203,66 @@ SurfaceControl::Surface& SurfaceControl::Surface::operator=(Surface&& other) {
}
SurfaceControl::Transaction::Transaction() {
- transaction_ =
- SurfaceControlMethods::Get().ASurfaceControl_CreateTransactionFn();
+ transaction_ = SurfaceControlMethods::Get().ASurfaceTransaction_createFn();
DCHECK(transaction_);
}
SurfaceControl::Transaction::~Transaction() {
- SurfaceControlMethods::Get().ASurfaceControl_DeleteTransactionFn(
- transaction_);
+ SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_);
}
void SurfaceControl::Transaction::SetVisibility(const Surface& surface,
bool show) {
- SurfaceControlMethods::Get().ASurfaceControl_TransactionSetVisibilityFn(
+ SurfaceControlMethods::Get().ASurfaceTransaction_setVisibilityFn(
transaction_, surface.surface(), show);
}
void SurfaceControl::Transaction::SetZOrder(const Surface& surface, int32_t z) {
- SurfaceControlMethods::Get().ASurfaceControl_TransactionSetZOrderFn(
+ SurfaceControlMethods::Get().ASurfaceTransaction_setZOrderFn(
transaction_, surface.surface(), z);
}
void SurfaceControl::Transaction::SetBuffer(const Surface& surface,
AHardwareBuffer* buffer,
base::ScopedFD fence_fd) {
- SurfaceControlMethods::Get().ASurfaceControl_TransactionSetBufferFn(
+ SurfaceControlMethods::Get().ASurfaceTransaction_setBufferFn(
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::SetGeometry(const Surface& surface,
+ const gfx::Rect& src,
+ const gfx::Rect& dst,
+ gfx::OverlayTransform transform) {
+ SurfaceControlMethods::Get().ASurfaceTransaction_setGeometryFn(
+ transaction_, surface.surface(), RectToARect(src), RectToARect(dst),
+ OverlayTransformToWindowTransform(transform));
}
void SurfaceControl::Transaction::SetOpaque(const Surface& surface,
bool opaque) {
- SurfaceControlMethods::Get().ASurfaceControl_TransactionSetBufferOpaqueFn(
- transaction_, surface.surface(), opaque);
+ int8_t transparency = opaque ? ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE
+ : ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT;
+ SurfaceControlMethods::Get().ASurfaceTransaction_setBufferTransparencyFn(
+ transaction_, surface.surface(), transparency);
}
void SurfaceControl::Transaction::SetDamageRect(const Surface& surface,
const gfx::Rect& rect) {
auto a_rect = RectToARect(rect);
- SurfaceControlMethods::Get().ASurfaceControl_TransactionSetDamageRegionFn(
+ SurfaceControlMethods::Get().ASurfaceTransaction_setDamageRegionFn(
transaction_, surface.surface(), &a_rect, 1u);
}
-void SurfaceControl::Transaction::SetCompletedFunc(
- TransactionCompletedFunc func,
+void SurfaceControl::Transaction::SetOnCompleteFunc(
+ ASurfaceTransaction_OnComplete func,
void* ctx) {
- SurfaceControlMethods::Get().ASurfaceControl_TransactionSetCompletedFuncFn(
- transaction_, ctx, func);
+ SurfaceControlMethods::Get().ASurfaceTransaction_setOnCompleteFn(transaction_,
+ ctx, func);
}
void SurfaceControl::Transaction::Apply() {
- SurfaceControlMethods::Get().ASurfaceControl_TransactionApplyFn(transaction_);
+ SurfaceControlMethods::Get().ASurfaceTransaction_applyFn(transaction_);
}
} // namespace gl
diff --git a/chromium/ui/gl/android/android_surface_control_compat.h b/chromium/ui/gl/android/android_surface_control_compat.h
index 0c3434ff2c3..111f7d51c14 100644
--- a/chromium/ui/gl/android/android_surface_control_compat.h
+++ b/chromium/ui/gl/android/android_surface_control_compat.h
@@ -12,13 +12,14 @@
#include "base/files/scoped_file.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/overlay_transform.h"
#include "ui/gl/gl_export.h"
extern "C" {
-typedef struct ASurface ASurface;
+typedef struct ASurfaceControl ASurfaceControl;
typedef struct ASurfaceTransaction ASurfaceTransaction;
-typedef void (*TransactionCompletedFunc)(void* context,
- int64_t present_time_ns);
+typedef void (*ASurfaceTransaction_OnComplete)(void* context,
+ int32_t present_fence);
}
namespace gl {
@@ -37,10 +38,10 @@ class GL_EXPORT SurfaceControl {
Surface(Surface&& other);
Surface& operator=(Surface&& other);
- ASurface* surface() const { return surface_; }
+ ASurfaceControl* surface() const { return surface_; }
private:
- ASurface* surface_ = nullptr;
+ ASurfaceControl* surface_ = nullptr;
};
class GL_EXPORT Transaction {
@@ -53,11 +54,13 @@ class GL_EXPORT SurfaceControl {
void SetBuffer(const Surface& surface,
AHardwareBuffer* buffer,
base::ScopedFD fence_fd);
- void SetCropRect(const Surface& surface, const gfx::Rect& rect);
- void SetDisplayFrame(const Surface& surface, const gfx::Rect& rect);
+ void SetGeometry(const Surface& surface,
+ const gfx::Rect& src,
+ const gfx::Rect& dst,
+ gfx::OverlayTransform transform);
void SetOpaque(const Surface& surface, bool opaque);
void SetDamageRect(const Surface& surface, const gfx::Rect& rect);
- void SetCompletedFunc(TransactionCompletedFunc func, void* ctx);
+ void SetOnCompleteFunc(ASurfaceTransaction_OnComplete func, void* ctx);
void Apply();
private:
diff --git a/chromium/ui/gl/angle_platform_impl.cc b/chromium/ui/gl/angle_platform_impl.cc
index 4a0bc9aef25..4e144067721 100644
--- a/chromium/ui/gl/angle_platform_impl.cc
+++ b/chromium/ui/gl/angle_platform_impl.cc
@@ -66,12 +66,13 @@ TraceEventHandle ANGLEPlatformImpl_addTraceEvent(
unsigned char flags) {
base::TimeTicks timestamp_tt =
base::TimeTicks() + base::TimeDelta::FromSecondsD(timestamp);
+ base::trace_event::TraceArguments args(num_args, arg_names, arg_types,
+ arg_values);
base::trace_event::TraceEventHandle handle =
TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
phase, category_group_enabled, name,
trace_event_internal::kGlobalScope, id, trace_event_internal::kNoId,
- base::PlatformThread::CurrentId(), timestamp_tt, num_args, arg_names,
- arg_types, arg_values, nullptr, flags);
+ base::PlatformThread::CurrentId(), timestamp_tt, &args, flags);
TraceEventHandle result;
memcpy(&result, &handle, sizeof(result));
return result;
diff --git a/chromium/ui/gl/dc_renderer_layer_params.cc b/chromium/ui/gl/dc_renderer_layer_params.cc
index 479dcf68032..c937bad980f 100644
--- a/chromium/ui/gl/dc_renderer_layer_params.cc
+++ b/chromium/ui/gl/dc_renderer_layer_params.cc
@@ -8,33 +8,10 @@
namespace ui {
+DCRendererLayerParams::DCRendererLayerParams() = default;
DCRendererLayerParams::DCRendererLayerParams(
- bool is_clipped,
- const gfx::Rect clip_rect,
- int z_order,
- const gfx::Transform& transform,
- std::vector<scoped_refptr<gl::GLImage>> image,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter,
- ProtectedVideoType protected_video_type)
- : is_clipped(is_clipped),
- clip_rect(clip_rect),
- z_order(z_order),
- transform(transform),
- image(image),
- contents_rect(contents_rect),
- rect(rect),
- background_color(background_color),
- edge_aa_mask(edge_aa_mask),
- opacity(opacity),
- filter(filter),
- protected_video_type(protected_video_type) {}
-
-DCRendererLayerParams::DCRendererLayerParams(
+ const DCRendererLayerParams& other) = default;
+DCRendererLayerParams& DCRendererLayerParams::operator=(
const DCRendererLayerParams& other) = default;
DCRendererLayerParams::~DCRendererLayerParams() = default;
diff --git a/chromium/ui/gl/dc_renderer_layer_params.h b/chromium/ui/gl/dc_renderer_layer_params.h
index d3ea2ab1cfe..7cd6ae24c30 100644
--- a/chromium/ui/gl/dc_renderer_layer_params.h
+++ b/chromium/ui/gl/dc_renderer_layer_params.h
@@ -29,58 +29,34 @@ enum class ProtectedVideoType : uint32_t {
};
struct GL_EXPORT DCRendererLayerParams {
- DCRendererLayerParams(bool is_clipped,
- const gfx::Rect clip_rect,
- int z_order,
- const gfx::Transform& transform,
- std::vector<scoped_refptr<gl::GLImage>> image,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter,
- ProtectedVideoType protected_video_type);
+ DCRendererLayerParams();
DCRendererLayerParams(const DCRendererLayerParams& other);
+ DCRendererLayerParams& operator=(const DCRendererLayerParams& other);
~DCRendererLayerParams();
- bool is_clipped;
- const gfx::Rect clip_rect;
- int z_order;
- const gfx::Transform transform;
- std::vector<scoped_refptr<gl::GLImage>> image;
- const gfx::RectF contents_rect;
- const gfx::Rect rect;
- unsigned background_color;
- unsigned edge_aa_mask;
- float opacity;
- unsigned filter;
- ProtectedVideoType protected_video_type;
-
- // This is a subset of cc::FilterOperation::FilterType.
- enum class FilterEffectType : uint32_t {
- GRAYSDCLE,
- SEPIA,
- SATURATE,
- HUE_ROTATE,
- INVERT,
- BRIGHTNESS,
- CONTRAST,
- OPACITY,
- BLUR,
- DROP_SHADOW,
- };
- struct GL_EXPORT FilterEffect {
- FilterEffectType type = FilterEffectType::GRAYSDCLE;
-
- // For every filter other than DROP_SHADOW, only |amount| is populated.
- float amount = 0;
- gfx::Point drop_shadow_offset;
- SkColor drop_shadow_color = 0;
- };
- using FilterEffects = std::vector<FilterEffect>;
-
- FilterEffects filter_effects;
+ // Images to display in overlay. There can either be one NV12 GPU buffer with
+ // both Y and UV planes, or two software buffers one each for Y and UV planes.
+ scoped_refptr<gl::GLImage> y_image;
+ scoped_refptr<gl::GLImage> uv_image;
+
+ // Stacking order relative to backbuffer which has z-order 0.
+ int z_order = 1;
+
+ // What part of the content to display in pixels.
+ gfx::Rect content_rect;
+
+ // Bounds of the overlay in pre-transform space.
+ gfx::Rect quad_rect;
+
+ // 2D flattened transform that maps |quad_rect| to root target space,
+ // after applying the |quad_rect.origin()| as an offset.
+ gfx::Transform transform;
+
+ // If |is_clipped| is true, then clip to |clip_rect| in root target space.
+ bool is_clipped = false;
+ gfx::Rect clip_rect;
+
+ ProtectedVideoType protected_video_type = ProtectedVideoType::kClear;
};
} // namespace ui
diff --git a/chromium/ui/gl/generate_bindings.py b/chromium/ui/gl/generate_bindings.py
index 6d5edc9cd4f..a3841e7f751 100755
--- a/chromium/ui/gl/generate_bindings.py
+++ b/chromium/ui/gl/generate_bindings.py
@@ -925,7 +925,7 @@ GL_FUNCTIONS = [
'names': ['glGetProgramPipelineiv'],
'arguments':
'GLuint pipeline, GLenum pname, GLint* params', },
-{ 'return_type': 'void',
+{ 'return_type': 'GLuint',
'names': ['glGetProgramResourceIndex'],
'arguments':
'GLuint program, GLenum programInterface, const GLchar* name', },
diff --git a/chromium/ui/gl/gl_api_unittest.cc b/chromium/ui/gl/gl_api_unittest.cc
index b28b76d9f0e..7dc66882a87 100644
--- a/chromium/ui/gl/gl_api_unittest.cc
+++ b/chromium/ui/gl/gl_api_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/command_line.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_gl_api_implementation.h"
@@ -152,7 +152,7 @@ TEST_F(GLApiTest, DisabledExtensionBitTest) {
};
static const char* kFakeDisabledExtensions = "GL_ARB_timer_query";
- SetFakeExtensionStrings(kFakeExtensions, arraysize(kFakeExtensions));
+ SetFakeExtensionStrings(kFakeExtensions, base::size(kFakeExtensions));
InitializeAPI(nullptr);
EXPECT_TRUE(driver_->ext.b_GL_ARB_timer_query);
@@ -173,17 +173,17 @@ TEST_F(GLApiTest, DisabledExtensionStringIndexTest) {
"GL_EXT_4"
};
- SetFakeExtensionStrings(kFakeExtensions, arraysize(kFakeExtensions));
+ SetFakeExtensionStrings(kFakeExtensions, base::size(kFakeExtensions));
InitializeAPI(nullptr);
- EXPECT_EQ(arraysize(kFakeExtensions), GetNumExtensions());
- for (uint32_t i = 0; i < arraysize(kFakeExtensions); ++i) {
+ EXPECT_EQ(base::size(kFakeExtensions), GetNumExtensions());
+ for (uint32_t i = 0; i < base::size(kFakeExtensions); ++i) {
EXPECT_STREQ(kFakeExtensions[i], GetExtensioni(i));
}
InitializeAPI(kFakeDisabledExtensions);
- EXPECT_EQ(arraysize(kFilteredExtensions), GetNumExtensions());
- for (uint32_t i = 0; i < arraysize(kFilteredExtensions); ++i) {
+ EXPECT_EQ(base::size(kFilteredExtensions), GetNumExtensions());
+ for (uint32_t i = 0; i < base::size(kFilteredExtensions); ++i) {
EXPECT_STREQ(kFilteredExtensions[i], GetExtensioni(i));
}
}
diff --git a/chromium/ui/gl/gl_bindings.h b/chromium/ui/gl/gl_bindings.h
index dd756620a91..3524f41b40e 100644
--- a/chromium/ui/gl/gl_bindings.h
+++ b/chromium/ui/gl/gl_bindings.h
@@ -436,11 +436,12 @@
#define GL_BINDING_CALL
#endif
+#if defined(NDEBUG) && !defined(GPU_ENABLE_SERVICE_LOGGING)
#define GL_SERVICE_LOG(args) DLOG(INFO) << args;
-#if defined(NDEBUG)
- #define GL_SERVICE_LOG_CODE_BLOCK(code)
+#define GL_SERVICE_LOG_CODE_BLOCK(code)
#else
- #define GL_SERVICE_LOG_CODE_BLOCK(code) code
+#define GL_SERVICE_LOG(args) LOG(INFO) << args;
+#define GL_SERVICE_LOG_CODE_BLOCK(code) code
#endif
// ANGLE_multiview constants.
diff --git a/chromium/ui/gl/gl_bindings_api_autogen_gl.h b/chromium/ui/gl/gl_bindings_api_autogen_gl.h
index b36d9e8f959..15956568158 100644
--- a/chromium/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/chromium/ui/gl/gl_bindings_api_autogen_gl.h
@@ -607,9 +607,9 @@ void glGetProgramPipelineInfoLogFn(GLuint pipeline,
void glGetProgramPipelineivFn(GLuint pipeline,
GLenum pname,
GLint* params) override;
-void glGetProgramResourceIndexFn(GLuint program,
- GLenum programInterface,
- const GLchar* name) override;
+GLuint glGetProgramResourceIndexFn(GLuint program,
+ GLenum programInterface,
+ const GLchar* name) override;
void glGetProgramResourceivFn(GLuint program,
GLenum programInterface,
GLuint index,
diff --git a/chromium/ui/gl/gl_bindings_autogen_gl.cc b/chromium/ui/gl/gl_bindings_autogen_gl.cc
index d9780a4a473..552fdcfa665 100644
--- a/chromium/ui/gl/gl_bindings_autogen_gl.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_gl.cc
@@ -3935,10 +3935,11 @@ void GLApiBase::glGetProgramPipelineivFn(GLuint pipeline,
driver_->fn.glGetProgramPipelineivFn(pipeline, pname, params);
}
-void GLApiBase::glGetProgramResourceIndexFn(GLuint program,
- GLenum programInterface,
- const GLchar* name) {
- driver_->fn.glGetProgramResourceIndexFn(program, programInterface, name);
+GLuint GLApiBase::glGetProgramResourceIndexFn(GLuint program,
+ GLenum programInterface,
+ const GLchar* name) {
+ return driver_->fn.glGetProgramResourceIndexFn(program, programInterface,
+ name);
}
void GLApiBase::glGetProgramResourceivFn(GLuint program,
@@ -7220,11 +7221,11 @@ void TraceGLApi::glGetProgramPipelineivFn(GLuint pipeline,
gl_api_->glGetProgramPipelineivFn(pipeline, pname, params);
}
-void TraceGLApi::glGetProgramResourceIndexFn(GLuint program,
- GLenum programInterface,
- const GLchar* name) {
+GLuint TraceGLApi::glGetProgramResourceIndexFn(GLuint program,
+ GLenum programInterface,
+ const GLchar* name) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramResourceIndex")
- gl_api_->glGetProgramResourceIndexFn(program, programInterface, name);
+ return gl_api_->glGetProgramResourceIndexFn(program, programInterface, name);
}
void TraceGLApi::glGetProgramResourceivFn(GLuint program,
@@ -11291,14 +11292,17 @@ void DebugGLApi::glGetProgramPipelineivFn(GLuint pipeline,
gl_api_->glGetProgramPipelineivFn(pipeline, pname, params);
}
-void DebugGLApi::glGetProgramResourceIndexFn(GLuint program,
- GLenum programInterface,
- const GLchar* name) {
+GLuint DebugGLApi::glGetProgramResourceIndexFn(GLuint program,
+ GLenum programInterface,
+ const GLchar* name) {
GL_SERVICE_LOG("glGetProgramResourceIndex"
<< "(" << program << ", "
<< GLEnums::GetStringEnum(programInterface) << ", "
<< static_cast<const void*>(name) << ")");
- gl_api_->glGetProgramResourceIndexFn(program, programInterface, name);
+ GLuint result =
+ gl_api_->glGetProgramResourceIndexFn(program, programInterface, name);
+ GL_SERVICE_LOG("GL_RESULT: " << result);
+ return result;
}
void DebugGLApi::glGetProgramResourceivFn(GLuint program,
@@ -15331,10 +15335,11 @@ void NoContextGLApi::glGetProgramPipelineivFn(GLuint pipeline,
NoContextHelper("glGetProgramPipelineiv");
}
-void NoContextGLApi::glGetProgramResourceIndexFn(GLuint program,
- GLenum programInterface,
- const GLchar* name) {
+GLuint NoContextGLApi::glGetProgramResourceIndexFn(GLuint program,
+ GLenum programInterface,
+ const GLchar* name) {
NoContextHelper("glGetProgramResourceIndex");
+ return 0U;
}
void NoContextGLApi::glGetProgramResourceivFn(GLuint program,
diff --git a/chromium/ui/gl/gl_bindings_autogen_gl.h b/chromium/ui/gl/gl_bindings_autogen_gl.h
index 8b83c70bbe2..a91d0c9403f 100644
--- a/chromium/ui/gl/gl_bindings_autogen_gl.h
+++ b/chromium/ui/gl/gl_bindings_autogen_gl.h
@@ -703,7 +703,7 @@ typedef void(GL_BINDING_CALL* glGetProgramPipelineInfoLogProc)(GLuint pipeline,
typedef void(GL_BINDING_CALL* glGetProgramPipelineivProc)(GLuint pipeline,
GLenum pname,
GLint* params);
-typedef void(GL_BINDING_CALL* glGetProgramResourceIndexProc)(
+typedef GLuint(GL_BINDING_CALL* glGetProgramResourceIndexProc)(
GLuint program,
GLenum programInterface,
const GLchar* name);
@@ -2943,9 +2943,9 @@ class GL_EXPORT GLApi {
virtual void glGetProgramPipelineivFn(GLuint pipeline,
GLenum pname,
GLint* params) = 0;
- virtual void glGetProgramResourceIndexFn(GLuint program,
- GLenum programInterface,
- const GLchar* name) = 0;
+ virtual GLuint glGetProgramResourceIndexFn(GLuint program,
+ GLenum programInterface,
+ const GLchar* name) = 0;
virtual void glGetProgramResourceivFn(GLuint program,
GLenum programInterface,
GLuint index,
diff --git a/chromium/ui/gl/gl_bindings_autogen_mock.cc b/chromium/ui/gl/gl_bindings_autogen_mock.cc
index 33dc1aa73c4..7bc41547667 100644
--- a/chromium/ui/gl/gl_bindings_autogen_mock.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_mock.cc
@@ -2029,12 +2029,12 @@ MockGLInterface::Mock_glGetProgramPipelineiv(GLuint pipeline,
interface_->GetProgramPipelineiv(pipeline, pname, params);
}
-void GL_BINDING_CALL
+GLuint GL_BINDING_CALL
MockGLInterface::Mock_glGetProgramResourceIndex(GLuint program,
GLenum programInterface,
const GLchar* name) {
MakeGlMockFunctionUnique("glGetProgramResourceIndex");
- interface_->GetProgramResourceIndex(program, programInterface, name);
+ return interface_->GetProgramResourceIndex(program, programInterface, name);
}
GLint GL_BINDING_CALL
diff --git a/chromium/ui/gl/gl_bindings_autogen_mock.h b/chromium/ui/gl/gl_bindings_autogen_mock.h
index d3a5c646cc0..eaab4683e42 100644
--- a/chromium/ui/gl/gl_bindings_autogen_mock.h
+++ b/chromium/ui/gl/gl_bindings_autogen_mock.h
@@ -850,7 +850,7 @@ static void GL_BINDING_CALL Mock_glGetProgramPipelineInfoLog(GLuint pipeline,
static void GL_BINDING_CALL Mock_glGetProgramPipelineiv(GLuint pipeline,
GLenum pname,
GLint* params);
-static void GL_BINDING_CALL
+static GLuint GL_BINDING_CALL
Mock_glGetProgramResourceIndex(GLuint program,
GLenum programInterface,
const GLchar* name);
diff --git a/chromium/ui/gl/gl_context.cc b/chromium/ui/gl/gl_context.cc
index abbacc0dcd7..af8acbffcc6 100644
--- a/chromium/ui/gl/gl_context.cc
+++ b/chromium/ui/gl/gl_context.cc
@@ -289,6 +289,7 @@ bool GLContext::WasAllocatedUsingRobustnessExtension() {
void GLContext::InitializeDynamicBindings() {
DCHECK(IsCurrent(nullptr));
+ BindGLApi();
DCHECK(static_bindings_initialized_);
if (!dynamic_bindings_initialized_) {
if (real_gl_api_) {
diff --git a/chromium/ui/gl/gl_image.cc b/chromium/ui/gl/gl_image.cc
index 48b5a04d5aa..9a45aed7e13 100644
--- a/chromium/ui/gl/gl_image.cc
+++ b/chromium/ui/gl/gl_image.cc
@@ -4,6 +4,10 @@
#include "ui/gl/gl_image.h"
+#if defined(OS_ANDROID)
+#include "base/android/scoped_hardware_buffer_fence_sync.h"
+#endif
+
namespace gl {
bool GLImage::BindTexImageWithInternalformat(unsigned target,
@@ -20,20 +24,10 @@ GLImage::Type GLImage::GetType() const {
}
#if defined(OS_ANDROID)
-std::unique_ptr<GLImage::ScopedHardwareBuffer> GLImage::GetAHardwareBuffer() {
+std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+GLImage::GetAHardwareBuffer() {
return nullptr;
}
-
-GLImage::ScopedHardwareBuffer::ScopedHardwareBuffer(
- base::android::ScopedHardwareBufferHandle handle,
- base::ScopedFD fence_fd)
- : handle_(std::move(handle)), fence_fd_(std::move(fence_fd)) {}
-
-GLImage::ScopedHardwareBuffer::~ScopedHardwareBuffer() = default;
-
-base::ScopedFD GLImage::ScopedHardwareBuffer::TakeFence() {
- return std::move(fence_fd_);
-}
#endif
} // namespace gl
diff --git a/chromium/ui/gl/gl_image.h b/chromium/ui/gl/gl_image.h
index 640ad8edaf1..ae0407d47e8 100644
--- a/chromium/ui/gl/gl_image.h
+++ b/chromium/ui/gl/gl_image.h
@@ -24,6 +24,7 @@
#if defined(OS_ANDROID)
#include <android/hardware_buffer.h>
+#include <memory>
#include "base/android/scoped_hardware_buffer_handle.h"
#include "base/files/scoped_file.h"
#endif
@@ -31,8 +32,12 @@
namespace base {
namespace trace_event {
class ProcessMemoryDump;
-}
-}
+} // namespace trace_event
+
+namespace android {
+class ScopedHardwareBufferFenceSync;
+} // namespace android
+} // namespace base
namespace gfx {
class GpuFence;
@@ -112,27 +117,14 @@ class GL_EXPORT GLImage : public base::RefCounted<GLImage> {
virtual bool EmulatingRGB() const;
#if defined(OS_ANDROID)
- class GL_EXPORT ScopedHardwareBuffer {
- public:
- ScopedHardwareBuffer(base::android::ScopedHardwareBufferHandle handle,
- base::ScopedFD fence_fd);
- virtual ~ScopedHardwareBuffer();
-
- AHardwareBuffer* buffer() const { return handle_.get(); }
- base::ScopedFD TakeFence();
-
- private:
- base::android::ScopedHardwareBufferHandle handle_;
- base::ScopedFD fence_fd_;
- };
-
// Provides the buffer backing this image, if it is backed by an
// AHardwareBuffer. The ScopedHardwareBuffer returned may include a fence
// which will be signaled when all pending work for the buffer has been
// finished and it can be safely read from.
// The buffer is guaranteed to be valid until the lifetime of the object
// returned.
- virtual std::unique_ptr<ScopedHardwareBuffer> GetAHardwareBuffer();
+ virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+ GetAHardwareBuffer();
#endif
// An identifier for subclasses. Necessary for safe downcasting.
diff --git a/chromium/ui/gl/gl_image_ahardwarebuffer.cc b/chromium/ui/gl/gl_image_ahardwarebuffer.cc
index 89e97dcf894..1f2b248172e 100644
--- a/chromium/ui/gl/gl_image_ahardwarebuffer.cc
+++ b/chromium/ui/gl/gl_image_ahardwarebuffer.cc
@@ -3,10 +3,37 @@
// found in the LICENSE file.
#include "ui/gl/gl_image_ahardwarebuffer.h"
+#include "base/android/android_hardware_buffer_compat.h"
+#include "base/android/scoped_hardware_buffer_fence_sync.h"
#include "ui/gl/gl_bindings.h"
namespace gl {
+namespace {
+
+uint32_t GetBufferFormat(const AHardwareBuffer* buffer) {
+ AHardwareBuffer_Desc desc = {};
+ base::AndroidHardwareBufferCompat::GetInstance().Describe(buffer, &desc);
+ return desc.format;
+}
+
+unsigned int GLInternalFormat(uint32_t buffer_format) {
+ switch (buffer_format) {
+ case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+ return GL_RGBA;
+ case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+ return GL_RGB;
+ default:
+ // For all other buffer formats, use GL_RGBA as internal format.
+ return GL_RGBA;
+ }
+}
+
+} // namespace
GLImageAHardwareBuffer::GLImageAHardwareBuffer(const gfx::Size& size)
: GLImageEGL(size) {}
@@ -16,6 +43,8 @@ GLImageAHardwareBuffer::~GLImageAHardwareBuffer() {}
bool GLImageAHardwareBuffer::Initialize(AHardwareBuffer* buffer,
bool preserved) {
handle_ = base::android::ScopedHardwareBufferHandle::Create(buffer);
+ uint32_t buffer_format = GetBufferFormat(buffer);
+ internal_format_ = GLInternalFormat(buffer_format);
EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, preserved ? EGL_TRUE : EGL_FALSE,
EGL_NONE};
EGLClientBuffer client_buffer = eglGetNativeClientBufferANDROID(buffer);
@@ -24,7 +53,7 @@ bool GLImageAHardwareBuffer::Initialize(AHardwareBuffer* buffer,
}
unsigned GLImageAHardwareBuffer::GetInternalFormat() {
- return GL_RGBA;
+ return internal_format_;
}
bool GLImageAHardwareBuffer::CopyTexImage(unsigned target) {
@@ -55,9 +84,9 @@ void GLImageAHardwareBuffer::OnMemoryDump(
uint64_t process_tracing_id,
const std::string& dump_name) {}
-std::unique_ptr<GLImage::ScopedHardwareBuffer>
+std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GLImageAHardwareBuffer::GetAHardwareBuffer() {
- return std::make_unique<ScopedHardwareBuffer>(
+ return std::make_unique<base::android::ScopedHardwareBufferFenceSync>(
base::android::ScopedHardwareBufferHandle::Create(handle_.get()),
base::ScopedFD());
}
diff --git a/chromium/ui/gl/gl_image_ahardwarebuffer.h b/chromium/ui/gl/gl_image_ahardwarebuffer.h
index c2241dbcc7c..febdedc30e9 100644
--- a/chromium/ui/gl/gl_image_ahardwarebuffer.h
+++ b/chromium/ui/gl/gl_image_ahardwarebuffer.h
@@ -5,12 +5,20 @@
#ifndef UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_
#define UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_
+#include <memory>
+
#include "base/android/scoped_hardware_buffer_handle.h"
#include "base/macros.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_image_egl.h"
+namespace base {
+namespace android {
+class ScopedHardwareBufferFenceSync;
+} // namespace android
+} // namespace base
+
namespace gl {
class GL_EXPORT GLImageAHardwareBuffer : public GLImageEGL {
@@ -38,13 +46,15 @@ class GL_EXPORT GLImageAHardwareBuffer : public GLImageEGL {
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
uint64_t process_tracing_id,
const std::string& dump_name) override;
- std::unique_ptr<ScopedHardwareBuffer> GetAHardwareBuffer() override;
+ std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+ GetAHardwareBuffer() override;
protected:
~GLImageAHardwareBuffer() override;
private:
base::android::ScopedHardwareBufferHandle handle_;
+ unsigned internal_format_ = GL_RGBA;
DISALLOW_COPY_AND_ASSIGN(GLImageAHardwareBuffer);
};
diff --git a/chromium/ui/gl/gl_image_dxgi.cc b/chromium/ui/gl/gl_image_dxgi.cc
index 877bb67ca5f..42ff2034544 100644
--- a/chromium/ui/gl/gl_image_dxgi.cc
+++ b/chromium/ui/gl/gl_image_dxgi.cc
@@ -138,40 +138,97 @@ EGLSurface CreatePbuffer(const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture,
} // namespace
-GLImageDXGIBase::GLImageDXGIBase(const gfx::Size& size) : size_(size) {}
+GLImageDXGI::GLImageDXGI(const gfx::Size& size, EGLStreamKHR stream)
+ : size_(size), stream_(stream) {}
// static
-GLImageDXGIBase* GLImageDXGIBase::FromGLImage(GLImage* image) {
+GLImageDXGI* GLImageDXGI::FromGLImage(GLImage* image) {
if (!image || image->GetType() != Type::DXGI_IMAGE)
return nullptr;
- return static_cast<GLImageDXGIBase*>(image);
+ return static_cast<GLImageDXGI*>(image);
}
-gfx::Size GLImageDXGIBase::GetSize() {
- return size_;
+bool GLImageDXGI::BindTexImage(unsigned target) {
+ if (!handle_.Get())
+ return true;
+
+ DCHECK(texture_);
+ DCHECK(keyed_mutex_);
+ if (!SupportedBindFormat(buffer_format_))
+ return false;
+
+ // Lazy-initialize surface_, as it is only used for binding.
+ if (surface_ == EGL_NO_SURFACE) {
+ EGLConfig config = ChooseCompatibleConfig(buffer_format_);
+ if (!config)
+ return false;
+ surface_ = CreatePbuffer(texture_, buffer_format_, config, target);
+ if (surface_ == EGL_NO_SURFACE)
+ return false;
+ }
+
+ // We don't wait, just return immediately.
+ HRESULT hrWait = keyed_mutex_->AcquireSync(KEY_BIND, 0);
+
+ if (hrWait == WAIT_TIMEOUT || hrWait == WAIT_ABANDONED || FAILED(hrWait)) {
+ NOTREACHED();
+ return false;
+ }
+
+ return eglBindTexImage(gl::GLSurfaceEGL::GetHardwareDisplay(), surface_,
+ EGL_BACK_BUFFER) == EGL_TRUE;
}
-unsigned GLImageDXGIBase::GetInternalFormat() {
- return GL_BGRA_EXT;
+bool GLImageDXGI::CopyTexImage(unsigned target) {
+ return false;
}
-bool GLImageDXGIBase::BindTexImage(unsigned target) {
+bool GLImageDXGI::CopyTexSubImage(unsigned target,
+ const gfx::Point& offset,
+ const gfx::Rect& rect) {
return false;
}
-void GLImageDXGIBase::ReleaseTexImage(unsigned target) {}
+void GLImageDXGI::Flush() {}
-bool GLImageDXGIBase::CopyTexImage(unsigned target) {
- return false;
+unsigned GLImageDXGI::GetInternalFormat() {
+ if (!handle_.Get())
+ return GL_BGRA_EXT;
+ else
+ return HasAlpha(buffer_format_) ? GL_RGBA : GL_RGB;
}
-bool GLImageDXGIBase::CopyTexSubImage(unsigned target,
- const gfx::Point& offset,
- const gfx::Rect& rect) {
- return false;
+gfx::Size GLImageDXGI::GetSize() {
+ return size_;
+}
+
+GLImage::Type GLImageDXGI::GetType() const {
+ return Type::DXGI_IMAGE;
+}
+
+void GLImageDXGI::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
+ uint64_t process_tracing_id,
+ const std::string& dump_name) {}
+
+void GLImageDXGI::ReleaseTexImage(unsigned target) {
+ if (!handle_.Get())
+ return;
+
+ DCHECK(texture_);
+ DCHECK(keyed_mutex_);
+
+ Microsoft::WRL::ComPtr<ID3D11Device> device =
+ QueryD3D11DeviceObjectFromANGLE();
+ Microsoft::WRL::ComPtr<ID3D11Device1> device1;
+ device.CopyTo(device1.GetAddressOf());
+
+ keyed_mutex_->ReleaseSync(KEY_RELEASE);
+
+ eglReleaseTexImage(gl::GLSurfaceEGL::GetHardwareDisplay(), surface_,
+ EGL_BACK_BUFFER);
}
-bool GLImageDXGIBase::ScheduleOverlayPlane(
+bool GLImageDXGI::ScheduleOverlayPlane(
gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
@@ -182,26 +239,36 @@ bool GLImageDXGIBase::ScheduleOverlayPlane(
return false;
}
-void GLImageDXGIBase::SetColorSpace(const gfx::ColorSpace& color_space) {
+void GLImageDXGI::SetColorSpace(const gfx::ColorSpace& color_space) {
color_space_ = color_space;
}
-void GLImageDXGIBase::Flush() {}
-
-void GLImageDXGIBase::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
- uint64_t process_tracing_id,
- const std::string& dump_name) {}
-
-GLImage::Type GLImageDXGIBase::GetType() const {
- return Type::DXGI_IMAGE;
-}
+bool GLImageDXGI::InitializeHandle(base::win::ScopedHandle handle,
+ uint32_t level,
+ gfx::BufferFormat format) {
+ level_ = level;
+ buffer_format_ = format;
+ Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
+ QueryD3D11DeviceObjectFromANGLE();
+ if (!d3d11_device)
+ return false;
-GLImageDXGIBase::~GLImageDXGIBase() {}
+ Microsoft::WRL::ComPtr<ID3D11Device1> d3d11_device1;
+ if (FAILED(d3d11_device.CopyTo(d3d11_device1.GetAddressOf())))
+ return false;
-GLImageDXGI::GLImageDXGI(const gfx::Size& size, EGLStreamKHR stream)
- : GLImageDXGIBase(size), stream_(stream) {}
+ if (FAILED(d3d11_device1->OpenSharedResource1(
+ handle.Get(), IID_PPV_ARGS(texture_.GetAddressOf())))) {
+ return false;
+ }
+ D3D11_TEXTURE2D_DESC desc;
+ texture_->GetDesc(&desc);
+ if (desc.ArraySize <= level_)
+ return false;
+ if (FAILED(texture_.CopyTo(keyed_mutex_.GetAddressOf())))
+ return false;
-bool GLImageDXGI::BindTexImage(unsigned target) {
+ handle_ = std::move(handle);
return true;
}
@@ -213,8 +280,14 @@ void GLImageDXGI::SetTexture(
}
GLImageDXGI::~GLImageDXGI() {
- EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
- eglDestroyStreamKHR(egl_display, stream_);
+ if (handle_.Get()) {
+ if (surface_ != EGL_NO_SURFACE) {
+ eglDestroySurface(gl::GLSurfaceEGL::GetHardwareDisplay(), surface_);
+ }
+ } else if (stream_) {
+ EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
+ eglDestroyStreamKHR(egl_display, stream_);
+ }
}
CopyingGLImageDXGI::CopyingGLImageDXGI(
@@ -343,89 +416,4 @@ bool CopyingGLImageDXGI::BindTexImage(unsigned target) {
CopyingGLImageDXGI::~CopyingGLImageDXGI() {}
-GLImageDXGIHandle::~GLImageDXGIHandle() {
- if (surface_ != EGL_NO_SURFACE) {
- eglDestroySurface(gl::GLSurfaceEGL::GetHardwareDisplay(), surface_);
- }
-}
-
-GLImageDXGIHandle::GLImageDXGIHandle(const gfx::Size& size,
- uint32_t level,
- gfx::BufferFormat format)
- : GLImageDXGIBase(size), format_(format) {
- level_ = level;
-}
-
-bool GLImageDXGIHandle::Initialize(base::win::ScopedHandle handle) {
- Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
- QueryD3D11DeviceObjectFromANGLE();
- if (!d3d11_device)
- return false;
-
- Microsoft::WRL::ComPtr<ID3D11Device1> d3d11_device1;
- if (FAILED(d3d11_device.CopyTo(d3d11_device1.GetAddressOf())))
- return false;
-
- if (FAILED(d3d11_device1->OpenSharedResource1(
- handle.Get(), IID_PPV_ARGS(texture_.GetAddressOf())))) {
- return false;
- }
- D3D11_TEXTURE2D_DESC desc;
- texture_->GetDesc(&desc);
- if (desc.ArraySize <= level_)
- return false;
- if (FAILED(texture_.CopyTo(keyed_mutex_.GetAddressOf())))
- return false;
-
- handle_ = std::move(handle);
- return true;
-}
-
-unsigned GLImageDXGIHandle::GetInternalFormat() {
- return HasAlpha(format_) ? GL_RGBA : GL_RGB;
-}
-
-bool GLImageDXGIHandle::BindTexImage(unsigned target) {
- DCHECK(texture_);
- DCHECK(keyed_mutex_);
- if (!SupportedBindFormat(format_))
- return false;
-
- // Lazy-initialize surface_, as it is only used for binding.
- if (surface_ == EGL_NO_SURFACE) {
- EGLConfig config = ChooseCompatibleConfig(format_);
- if (!config)
- return false;
- surface_ = CreatePbuffer(texture_, format_, config, target);
- if (surface_ == EGL_NO_SURFACE)
- return false;
- }
-
- // We don't wait, just return immediately.
- HRESULT hrWait = keyed_mutex_->AcquireSync(KEY_BIND, 0);
-
- if (hrWait == WAIT_TIMEOUT || hrWait == WAIT_ABANDONED || FAILED(hrWait)) {
- NOTREACHED();
- return false;
- }
-
- return eglBindTexImage(gl::GLSurfaceEGL::GetHardwareDisplay(), surface_,
- EGL_BACK_BUFFER) == EGL_TRUE;
-}
-
-void GLImageDXGIHandle::ReleaseTexImage(unsigned target) {
- DCHECK(texture_);
- DCHECK(keyed_mutex_);
-
- Microsoft::WRL::ComPtr<ID3D11Device> device =
- QueryD3D11DeviceObjectFromANGLE();
- Microsoft::WRL::ComPtr<ID3D11Device1> device1;
- device.CopyTo(device1.GetAddressOf());
-
- keyed_mutex_->ReleaseSync(KEY_RELEASE);
-
- eglReleaseTexImage(gl::GLSurfaceEGL::GetHardwareDisplay(), surface_,
- EGL_BACK_BUFFER);
-}
-
} // namespace gl
diff --git a/chromium/ui/gl/gl_image_dxgi.h b/chromium/ui/gl/gl_image_dxgi.h
index 98df76196c0..d685d93dfba 100644
--- a/chromium/ui/gl/gl_image_dxgi.h
+++ b/chromium/ui/gl/gl_image_dxgi.h
@@ -19,25 +19,27 @@ typedef void* EGLConfig;
typedef void* EGLSurface;
namespace gl {
-
-// TODO(776010): Reconcile the different GLImageDXGI types. Remove
-// GLImageDXGIHandle, and move its implementation into GLImageDXGI.
-class GL_EXPORT GLImageDXGIBase : public GLImage {
+class GL_EXPORT GLImageDXGI : public GLImage {
public:
- GLImageDXGIBase(const gfx::Size& size);
+ GLImageDXGI(const gfx::Size& size, EGLStreamKHR stream);
// Safe downcast. Returns nullptr on failure.
- static GLImageDXGIBase* FromGLImage(GLImage* image);
+ static GLImageDXGI* FromGLImage(GLImage* image);
// GLImage implementation.
- gfx::Size GetSize() override;
- unsigned GetInternalFormat() override;
bool BindTexImage(unsigned target) override;
- void ReleaseTexImage(unsigned target) override;
bool CopyTexImage(unsigned target) override;
bool CopyTexSubImage(unsigned target,
const gfx::Point& offset,
const gfx::Rect& rect) override;
+ void Flush() override;
+ unsigned GetInternalFormat() override;
+ gfx::Size GetSize() override;
+ Type GetType() const override;
+ void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
+ uint64_t process_tracing_id,
+ const std::string& dump_name) override;
+ void ReleaseTexImage(unsigned target) override;
bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
@@ -46,43 +48,30 @@ class GL_EXPORT GLImageDXGIBase : public GLImage {
bool enable_blend,
std::unique_ptr<gfx::GpuFence> gpu_fence) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override;
- void Flush() override;
- void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
- uint64_t process_tracing_id,
- const std::string& dump_name) override;
- Type GetType() const override;
- Microsoft::WRL::ComPtr<ID3D11Texture2D> texture() { return texture_; }
const gfx::ColorSpace& color_space() const { return color_space_; }
-
- size_t level() const { return level_; }
Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex() { return keyed_mutex_; }
+ size_t level() const { return level_; }
+ Microsoft::WRL::ComPtr<ID3D11Texture2D> texture() { return texture_; }
- protected:
- ~GLImageDXGIBase() override;
-
- gfx::Size size_;
- gfx::ColorSpace color_space_;
-
- Microsoft::WRL::ComPtr<ID3D11Texture2D> texture_;
- Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex_;
- size_t level_ = 0;
-};
-
-class GL_EXPORT GLImageDXGI : public GLImageDXGIBase {
- public:
- GLImageDXGI(const gfx::Size& size, EGLStreamKHR stream);
-
- // GLImage implementation.
- bool BindTexImage(unsigned target) override;
-
+ bool InitializeHandle(base::win::ScopedHandle handle,
+ uint32_t level,
+ gfx::BufferFormat format);
void SetTexture(const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture,
size_t level);
protected:
~GLImageDXGI() override;
- EGLStreamKHR stream_;
+ gfx::BufferFormat buffer_format_ = gfx::BufferFormat::BGRA_8888;
+ gfx::ColorSpace color_space_;
+ base::win::ScopedHandle handle_;
+ Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex_;
+ size_t level_ = 0;
+ gfx::Size size_;
+ EGLSurface surface_ = nullptr;
+ EGLStreamKHR stream_ = nullptr;
+ Microsoft::WRL::ComPtr<ID3D11Texture2D> texture_;
};
// This copies to a new texture on bind.
@@ -114,27 +103,6 @@ class GL_EXPORT CopyingGLImageDXGI : public GLImageDXGI {
Microsoft::WRL::ComPtr<ID3D11Texture2D> decoder_copy_texture_;
Microsoft::WRL::ComPtr<ID3D11VideoProcessorOutputView> output_view_;
};
-
-class GL_EXPORT GLImageDXGIHandle : public GLImageDXGIBase {
- public:
- GLImageDXGIHandle(const gfx::Size& size,
- uint32_t level,
- gfx::BufferFormat format);
-
- bool Initialize(base::win::ScopedHandle handle);
-
- // GLImage implementation.
- bool BindTexImage(unsigned target) override;
- unsigned GetInternalFormat() override;
- void ReleaseTexImage(unsigned target) override;
-
- protected:
- ~GLImageDXGIHandle() override;
-
- EGLSurface surface_ = nullptr;
- base::win::ScopedHandle handle_;
- gfx::BufferFormat format_;
-};
}
#endif // UI_GL_GL_IMAGE_DXGI_H_
diff --git a/chromium/ui/gl/gl_image_dxgi_unittest.cc b/chromium/ui/gl/gl_image_dxgi_unittest.cc
index 38c8b77d62f..b0057706977 100644
--- a/chromium/ui/gl/gl_image_dxgi_unittest.cc
+++ b/chromium/ui/gl/gl_image_dxgi_unittest.cc
@@ -66,9 +66,9 @@ class GLImageDXGITestDelegate : public GLImageTestDelegateBase {
nullptr, &handle);
EXPECT_HRESULT_SUCCEEDED(hr);
- scoped_refptr<GLImageDXGIHandle> image(
- new GLImageDXGIHandle(size, 0, format));
- bool rv = image->Initialize(base::win::ScopedHandle(handle));
+ scoped_refptr<GLImageDXGI> image(new GLImageDXGI(size, nullptr));
+ bool rv =
+ image->InitializeHandle(base::win::ScopedHandle(handle), 0, format);
EXPECT_TRUE(rv);
return image;
diff --git a/chromium/ui/gl/gl_image_io_surface.mm b/chromium/ui/gl/gl_image_io_surface.mm
index 5c84656101d..ae340a0a7a7 100644
--- a/chromium/ui/gl/gl_image_io_surface.mm
+++ b/chromium/ui/gl/gl_image_io_surface.mm
@@ -17,10 +17,10 @@
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/mac/display_icc_profiles.h"
#include "ui/gfx/mac/io_surface.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_enums.h"
-#include "ui/gl/gl_features.h"
#include "ui/gl/gl_version_info.h"
#include "ui/gl/scoped_binders.h"
#include "ui/gl/yuv_to_rgb_converter.h"
diff --git a/chromium/ui/gl/gl_image_io_surface_unittest.cc b/chromium/ui/gl/gl_image_io_surface_unittest.cc
index 3ec385e7496..e057fecbdc7 100644
--- a/chromium/ui/gl/gl_image_io_surface_unittest.cc
+++ b/chromium/ui/gl/gl_image_io_surface_unittest.cc
@@ -5,6 +5,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/buffer_format_util.h"
@@ -48,7 +49,7 @@ class GLImageIOSurfaceTestDelegate : public GLImageTestDelegateBase {
corrected_color[2] = color[0];
corrected_color[3] = color[3];
} else {
- memcpy(corrected_color, color, arraysize(corrected_color));
+ memcpy(corrected_color, color, base::size(corrected_color));
}
for (size_t plane = 0; plane < NumberOfPlanesForBufferFormat(format);
diff --git a/chromium/ui/gl/gl_image_native_pixmap.cc b/chromium/ui/gl/gl_image_native_pixmap.cc
index 9ab046fa7bb..a29c9c67a7a 100644
--- a/chromium/ui/gl/gl_image_native_pixmap.cc
+++ b/chromium/ui/gl/gl_image_native_pixmap.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/files/scoped_file.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/gpu_fence.h"
@@ -34,33 +35,38 @@
namespace gl {
namespace {
-bool ValidInternalFormat(unsigned internalformat, gfx::BufferFormat format) {
- switch (internalformat) {
- case GL_RGB:
- return format == gfx::BufferFormat::BGR_565 ||
- format == gfx::BufferFormat::RGBX_8888 ||
- format == gfx::BufferFormat::BGRX_8888;
- case GL_RGB10_A2_EXT:
- return format == gfx::BufferFormat::RGBX_1010102;
- case GL_RGB_YCRCB_420_CHROMIUM:
- return format == gfx::BufferFormat::YVU_420;
- case GL_RGB_YCBCR_420V_CHROMIUM:
- return format == gfx::BufferFormat::YUV_420_BIPLANAR;
- case GL_RGBA:
- return format == gfx::BufferFormat::RGBA_8888 ||
- format == gfx::BufferFormat::RGBX_1010102;
- case GL_BGRA_EXT:
- return format == gfx::BufferFormat::BGRA_8888 ||
- format == gfx::BufferFormat::BGRX_1010102;
- case GL_RED_EXT:
- return format == gfx::BufferFormat::R_8;
- case GL_R16_EXT:
- return format == gfx::BufferFormat::R_16;
- case GL_RG_EXT:
- return format == gfx::BufferFormat::RG_88;
- default:
- return false;
+// Returns corresponding internalformat if supported, and GL_NONE otherwise.
+unsigned GetInternalFormatFromFormat(gfx::BufferFormat format) {
+ switch (format) {
+ case gfx::BufferFormat::R_8:
+ return GL_RED_EXT;
+ case gfx::BufferFormat::R_16:
+ return GL_R16_EXT;
+ case gfx::BufferFormat::RG_88:
+ return GL_RG_EXT;
+ case gfx::BufferFormat::BGR_565:
+ case gfx::BufferFormat::RGBX_8888:
+ case gfx::BufferFormat::BGRX_8888:
+ return GL_RGB;
+ case gfx::BufferFormat::RGBA_8888:
+ return GL_RGBA;
+ case gfx::BufferFormat::RGBX_1010102:
+ return GL_RGB10_A2_EXT;
+ case gfx::BufferFormat::BGRA_8888:
+ return GL_BGRA_EXT;
+ case gfx::BufferFormat::YVU_420:
+ return GL_RGB_YCRCB_420_CHROMIUM;
+ case gfx::BufferFormat::YUV_420_BIPLANAR:
+ return GL_RGB_YCBCR_420V_CHROMIUM;
+ case gfx::BufferFormat::RGBA_4444:
+ case gfx::BufferFormat::BGRX_1010102:
+ case gfx::BufferFormat::RGBA_F16:
+ case gfx::BufferFormat::UYVY_422:
+ return GL_NONE;
}
+
+ NOTREACHED();
+ return GL_NONE;
}
EGLint FourCC(gfx::BufferFormat format) {
@@ -134,9 +140,9 @@ gfx::BufferFormat GetBufferFormatFromFourCCFormat(int format) {
} // namespace
GLImageNativePixmap::GLImageNativePixmap(const gfx::Size& size,
- unsigned internalformat)
+ gfx::BufferFormat format)
: GLImageEGL(size),
- internalformat_(internalformat),
+ format_(format),
has_image_flush_external_(
gl::GLSurfaceEGL::HasEGLExtension("EGL_EXT_image_flush_external")),
has_image_dma_buf_export_(
@@ -144,22 +150,13 @@ GLImageNativePixmap::GLImageNativePixmap(const gfx::Size& size,
GLImageNativePixmap::~GLImageNativePixmap() {}
-bool GLImageNativePixmap::Initialize(gfx::NativePixmap* pixmap,
- gfx::BufferFormat format) {
+bool GLImageNativePixmap::Initialize(gfx::NativePixmap* pixmap) {
DCHECK(!pixmap_);
+ if (GetInternalFormatFromFormat(format_) == GL_NONE) {
+ LOG(ERROR) << "Unsupported format: " << gfx::BufferFormatToString(format_);
+ return false;
+ }
if (pixmap->AreDmaBufFdsValid()) {
- if (!ValidFormat(format)) {
- LOG(ERROR) << "Invalid format: " << gfx::BufferFormatToString(format);
- return false;
- }
-
- if (!ValidInternalFormat(internalformat_, format)) {
- LOG(ERROR) << "Invalid internalformat: "
- << GLEnums::GetStringEnum(internalformat_)
- << " for format: " << gfx::BufferFormatToString(format);
- return false;
- }
-
// Note: If eglCreateImageKHR is successful for a EGL_LINUX_DMA_BUF_EXT
// target, the EGL will take a reference to the dma_buf.
std::vector<EGLint> attrs;
@@ -168,7 +165,7 @@ bool GLImageNativePixmap::Initialize(gfx::NativePixmap* pixmap,
attrs.push_back(EGL_HEIGHT);
attrs.push_back(size_.height());
attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
- attrs.push_back(FourCC(format));
+ attrs.push_back(FourCC(format_));
const EGLint kLinuxDrmModifiers[] = {EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
@@ -193,7 +190,7 @@ bool GLImageNativePixmap::Initialize(gfx::NativePixmap* pixmap,
if (has_dma_buf_import_modifier &&
pixmap->GetDmaBufModifier(0) != gfx::NativePixmapPlane::kNoModifier) {
uint64_t modifier = pixmap->GetDmaBufModifier(pixmap_plane);
- DCHECK(attrs_plane < arraysize(kLinuxDrmModifiers));
+ DCHECK(attrs_plane < base::size(kLinuxDrmModifiers));
attrs.push_back(kLinuxDrmModifiers[attrs_plane]);
attrs.push_back(modifier & 0xffffffff);
attrs.push_back(kLinuxDrmModifiers[attrs_plane] + 1);
@@ -214,6 +211,10 @@ bool GLImageNativePixmap::Initialize(gfx::NativePixmap* pixmap,
}
bool GLImageNativePixmap::InitializeFromTexture(uint32_t texture_id) {
+ if (GetInternalFormatFromFormat(format_) == GL_NONE) {
+ LOG(ERROR) << "Unsupported format: " << gfx::BufferFormatToString(format_);
+ return false;
+ }
GLContext* current_context = GLContext::GetCurrent();
if (!current_context || !current_context->IsCurrent(nullptr)) {
LOG(ERROR) << "No gl context bound to the current thread";
@@ -268,14 +269,16 @@ gfx::NativePixmapHandle GLImageNativePixmap::ExportHandle() {
return gfx::NativePixmapHandle();
}
- if (!ValidInternalFormat(internalformat_, format)) {
+ if (format != format_) {
// A driver has returned a format different than what has been requested.
// This can happen if RGBX is implemented using RGBA. Otherwise there is
// a real mistake from the user and we have to fail.
- if (internalformat_ == GL_RGB && format != gfx::BufferFormat::RGBA_8888) {
- LOG(ERROR) << "Invalid internalformat: "
- << GLEnums::GetStringEnum(internalformat_)
- << " for format: " << gfx::BufferFormatToString(format);
+ if (GetInternalFormat() == GL_RGB &&
+ format != gfx::BufferFormat::RGBA_8888) {
+ LOG(ERROR) << "Invalid driver format: "
+ << gfx::BufferFormatToString(format)
+ << " for requested format: "
+ << gfx::BufferFormatToString(format_);
return gfx::NativePixmapHandle();
}
}
@@ -324,19 +327,19 @@ gfx::NativePixmapHandle GLImageNativePixmap::ExportHandle() {
}
unsigned GLImageNativePixmap::GetInternalFormat() {
- return internalformat_;
+ return GetInternalFormatFromFormat(format_);
}
bool GLImageNativePixmap::CopyTexImage(unsigned target) {
- if (egl_image_ == EGL_NO_IMAGE_KHR) {
- // Pass-through image type fails to bind and copy; make sure we
- // don't draw with uninitialized texture.
- std::vector<unsigned char> data(size_.width() * size_.height() * 4);
- glTexImage2D(target, 0, GL_RGBA, size_.width(), size_.height(), 0, GL_RGBA,
- GL_UNSIGNED_BYTE, data.data());
- return true;
- }
- return false;
+ if (egl_image_ != EGL_NO_IMAGE_KHR)
+ return false;
+
+ // Pass-through image type fails to bind and copy; make sure we
+ // don't draw with uninitialized texture.
+ std::vector<unsigned char> data(size_.width() * size_.height() * 4);
+ glTexImage2D(target, 0, GL_RGBA, size_.width(), size_.height(), 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, data.data());
+ return true;
}
bool GLImageNativePixmap::CopyTexSubImage(unsigned target,
@@ -382,67 +385,4 @@ void GLImageNativePixmap::OnMemoryDump(
// TODO(ericrk): Implement GLImage OnMemoryDump. crbug.com/514914
}
-// static
-unsigned GLImageNativePixmap::GetInternalFormatForTesting(
- gfx::BufferFormat format) {
- DCHECK(ValidFormat(format));
- switch (format) {
- case gfx::BufferFormat::R_8:
- return GL_RED_EXT;
- case gfx::BufferFormat::R_16:
- return GL_R16_EXT;
- case gfx::BufferFormat::RG_88:
- return GL_RG_EXT;
- case gfx::BufferFormat::BGR_565:
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::BGRX_8888:
- return GL_RGB;
- case gfx::BufferFormat::RGBA_8888:
- return GL_RGBA;
- case gfx::BufferFormat::RGBX_1010102:
- return GL_RGB10_A2_EXT;
- case gfx::BufferFormat::BGRA_8888:
- return GL_BGRA_EXT;
- case gfx::BufferFormat::YVU_420:
- return GL_RGB_YCRCB_420_CHROMIUM;
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- return GL_RGB_YCBCR_420V_CHROMIUM;
- case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::BGRX_1010102:
- case gfx::BufferFormat::RGBA_F16:
- case gfx::BufferFormat::UYVY_422:
- NOTREACHED();
- return GL_NONE;
- }
-
- NOTREACHED();
- return GL_NONE;
-}
-
-// static
-bool GLImageNativePixmap::ValidFormat(gfx::BufferFormat format) {
- switch (format) {
- case gfx::BufferFormat::R_8:
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::RG_88:
- case gfx::BufferFormat::BGR_565:
- case gfx::BufferFormat::RGBA_8888:
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::BGRA_8888:
- case gfx::BufferFormat::BGRX_8888:
- case gfx::BufferFormat::RGBX_1010102:
- case gfx::BufferFormat::YVU_420:
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- return true;
- case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::BGRX_1010102:
- case gfx::BufferFormat::RGBA_F16:
- case gfx::BufferFormat::UYVY_422:
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
} // namespace gl
diff --git a/chromium/ui/gl/gl_image_native_pixmap.h b/chromium/ui/gl/gl_image_native_pixmap.h
index 8f91050d9f0..93160a1164b 100644
--- a/chromium/ui/gl/gl_image_native_pixmap.h
+++ b/chromium/ui/gl/gl_image_native_pixmap.h
@@ -17,10 +17,10 @@ namespace gl {
class GL_EXPORT GLImageNativePixmap : public gl::GLImageEGL {
public:
- GLImageNativePixmap(const gfx::Size& size, unsigned internalformat);
+ GLImageNativePixmap(const gfx::Size& size, gfx::BufferFormat format);
// Create an EGLImage from a given NativePixmap.
- bool Initialize(gfx::NativePixmap* pixmap, gfx::BufferFormat format);
+ bool Initialize(gfx::NativePixmap* pixmap);
// Create an EGLImage from a given GL texture.
bool InitializeFromTexture(uint32_t texture_id);
// Export the wrapped EGLImage to dmabuf fds.
@@ -45,15 +45,11 @@ class GL_EXPORT GLImageNativePixmap : public gl::GLImageEGL {
uint64_t process_tracing_id,
const std::string& dump_name) override;
- static unsigned GetInternalFormatForTesting(gfx::BufferFormat format);
-
protected:
~GLImageNativePixmap() override;
private:
- static bool ValidFormat(gfx::BufferFormat format);
-
- unsigned internalformat_;
+ gfx::BufferFormat format_;
scoped_refptr<gfx::NativePixmap> pixmap_;
bool has_image_flush_external_;
bool has_image_dma_buf_export_;
diff --git a/chromium/ui/gl/gl_image_native_pixmap_unittest.cc b/chromium/ui/gl/gl_image_native_pixmap_unittest.cc
index 49ed7027f17..6b2bcd69587 100644
--- a/chromium/ui/gl/gl_image_native_pixmap_unittest.cc
+++ b/chromium/ui/gl/gl_image_native_pixmap_unittest.cc
@@ -49,8 +49,7 @@ class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
- scoped_refptr<gl::GLImageNativePixmap> image(new gl::GLImageNativePixmap(
- size, gl::GLImageNativePixmap::GetInternalFormatForTesting(format)));
+ auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(size, format);
EXPECT_TRUE(image->InitializeFromTexture(texture_id));
glDeleteTextures(1, &texture_id);
diff --git a/chromium/ui/gl/gl_image_shared_memory.cc b/chromium/ui/gl/gl_image_shared_memory.cc
index d736cd2febe..8ffb8546f3e 100644
--- a/chromium/ui/gl/gl_image_shared_memory.cc
+++ b/chromium/ui/gl/gl_image_shared_memory.cc
@@ -9,7 +9,6 @@
#include "base/process/process_handle.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"
#include "ui/gfx/buffer_format_util.h"
@@ -70,9 +69,7 @@ void GLImageSharedMemory::OnMemoryDump(
base::trace_event::ProcessMemoryDump* pmd,
uint64_t process_tracing_id,
const std::string& dump_name) {
- size_t size_in_bytes = 0;
-
- size_in_bytes = stride() * GetSize().height();
+ const size_t size_in_bytes = stride() * GetSize().height();
// Dump under "/shared_memory", as the base class may also dump to
// "/texture_memory".
diff --git a/chromium/ui/gl/gl_implementation.cc b/chromium/ui/gl/gl_implementation.cc
index ad110e8fc5b..9234bb6f995 100644
--- a/chromium/ui/gl/gl_implementation.cc
+++ b/chromium/ui/gl/gl_implementation.cc
@@ -11,7 +11,6 @@
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/protected_memory.h"
#include "base/memory/protected_memory_cfi.h"
#include "base/stl_util.h"
@@ -19,8 +18,8 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_features.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_version_info.h"
@@ -111,7 +110,7 @@ GLXApi* g_current_glx_context;
#endif
GLImplementation GetNamedGLImplementation(const std::string& name) {
- for (size_t i = 0; i < arraysize(kGLImplementationNamePairs); ++i) {
+ for (size_t i = 0; i < base::size(kGLImplementationNamePairs); ++i) {
if (name == kGLImplementationNamePairs[i].name)
return kGLImplementationNamePairs[i].implementation;
}
@@ -124,7 +123,7 @@ GLImplementation GetSoftwareGLImplementation() {
}
const char* GetGLImplementationName(GLImplementation implementation) {
- for (size_t i = 0; i < arraysize(kGLImplementationNamePairs); ++i) {
+ for (size_t i = 0; i < base::size(kGLImplementationNamePairs); ++i) {
if (implementation == kGLImplementationNamePairs[i].implementation)
return kGLImplementationNamePairs[i].name;
}
diff --git a/chromium/ui/gl/gl_mock_autogen_gl.h b/chromium/ui/gl/gl_mock_autogen_gl.h
index 40ffe994c16..534700d23df 100644
--- a/chromium/ui/gl/gl_mock_autogen_gl.h
+++ b/chromium/ui/gl/gl_mock_autogen_gl.h
@@ -586,7 +586,9 @@ MOCK_METHOD4(
MOCK_METHOD3(GetProgramPipelineiv,
void(GLuint pipeline, GLenum pname, GLint* params));
MOCK_METHOD3(GetProgramResourceIndex,
- void(GLuint program, GLenum programInterface, const GLchar* name));
+ GLuint(GLuint program,
+ GLenum programInterface,
+ const GLchar* name));
MOCK_METHOD8(GetProgramResourceiv,
void(GLuint program,
GLenum programInterface,
diff --git a/chromium/ui/gl/gl_stub_autogen_gl.cc b/chromium/ui/gl/gl_stub_autogen_gl.cc
index cf0fc52d220..33f7dff4342 100644
--- a/chromium/ui/gl/gl_stub_autogen_gl.cc
+++ b/chromium/ui/gl/gl_stub_autogen_gl.cc
@@ -79,6 +79,12 @@ GLenum GLStubApiBase::glGetGraphicsResetStatusARBFn() {
return 0;
}
+GLuint GLStubApiBase::glGetProgramResourceIndexFn(GLuint program,
+ GLenum programInterface,
+ const GLchar* name) {
+ return 0;
+}
+
GLint GLStubApiBase::glGetProgramResourceLocationFn(GLuint program,
GLenum programInterface,
const char* name) {
diff --git a/chromium/ui/gl/gl_stub_autogen_gl.h b/chromium/ui/gl/gl_stub_autogen_gl.h
index 64a6a67bcf4..32cf931ea86 100644
--- a/chromium/ui/gl/gl_stub_autogen_gl.h
+++ b/chromium/ui/gl/gl_stub_autogen_gl.h
@@ -608,9 +608,9 @@ void glGetProgramPipelineInfoLogFn(GLuint pipeline,
void glGetProgramPipelineivFn(GLuint pipeline,
GLenum pname,
GLint* params) override {}
-void glGetProgramResourceIndexFn(GLuint program,
- GLenum programInterface,
- const GLchar* name) override {}
+GLuint glGetProgramResourceIndexFn(GLuint program,
+ GLenum programInterface,
+ const GLchar* name) override;
void glGetProgramResourceivFn(GLuint program,
GLenum programInterface,
GLuint index,
diff --git a/chromium/ui/gl/gl_surface_egl.cc b/chromium/ui/gl/gl_surface_egl.cc
index c447ed27b13..3e61b5f204d 100644
--- a/chromium/ui/gl/gl_surface_egl.cc
+++ b/chromium/ui/gl/gl_surface_egl.cc
@@ -61,6 +61,11 @@
#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363
#endif /* EGL_EXT_gl_colorspace_display_p3 */
+#ifndef EGL_EXT_gl_colorspace_display_p3_passthrough
+#define EGL_EXT_gl_colorspace_display_p3_passthrough 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT 0x3490
+#endif /* EGL_EXT_gl_colorspace_display_p3_passthrough */
+
// From ANGLE's egl/eglext.h.
#ifndef EGL_ANGLE_platform_angle
@@ -150,6 +155,7 @@ 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_egl_ext_colorspace_display_p3_passthrough = 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;
@@ -694,6 +700,8 @@ bool GLSurfaceEGL::InitializeOneOffCommon() {
g_egl_khr_colorspace = HasEGLExtension("EGL_KHR_gl_colorspace");
g_egl_ext_colorspace_display_p3 =
HasEGLExtension("EGL_EXT_gl_colorspace_display_p3");
+ g_egl_ext_colorspace_display_p3_passthrough =
+ HasEGLExtension("EGL_EXT_gl_colorspace_display_p3_passthrough");
// According to https://source.android.com/compatibility/android-cdd.html the
// EGL_IMG_context_priority extension is mandatory for Virtual Reality High
// Performance support, but due to a bug in Android Nougat the extension
@@ -1041,9 +1049,20 @@ bool NativeViewGLSurfaceEGL::Initialize(GLSurfaceFormat format) {
// with the P3 gamut instead of the the sRGB gamut.
// COLORSPACE_DISPLAY_P3_LINEAR has a linear transfer function, and is
// intended for use with 16-bit formats.
- if (g_egl_khr_colorspace && g_egl_ext_colorspace_display_p3) {
+ bool p3_supported = g_egl_ext_colorspace_display_p3 ||
+ g_egl_ext_colorspace_display_p3_passthrough;
+ if (g_egl_khr_colorspace && p3_supported) {
egl_window_attributes.push_back(EGL_GL_COLORSPACE_KHR);
- egl_window_attributes.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
+ // Chrome relied on incorrect Android behavior when dealing with P3 /
+ // framebuffer_srgb interactions. This behavior was fixed in Q, which
+ // causes invalid Chrome rendering. To achieve Android-P behavior in Q+,
+ // use EGL_GL_COLORSPACE_P3_PASSTHROUGH_EXT where possible.
+ if (g_egl_ext_colorspace_display_p3_passthrough) {
+ egl_window_attributes.push_back(
+ EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT);
+ } else {
+ egl_window_attributes.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
+ }
}
break;
}
diff --git a/chromium/ui/gl/gl_surface_egl_surface_control.cc b/chromium/ui/gl/gl_surface_egl_surface_control.cc
index 8eaaf175635..0411c431a86 100644
--- a/chromium/ui/gl/gl_surface_egl_surface_control.cc
+++ b/chromium/ui/gl/gl_surface_egl_surface_control.cc
@@ -5,6 +5,7 @@
#include "ui/gl/gl_surface_egl_surface_control.h"
#include "base/android/android_hardware_buffer_compat.h"
+#include "base/android/scoped_hardware_buffer_fence_sync.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"
@@ -24,16 +25,16 @@ gfx::Size GetBufferSize(const AHardwareBuffer* buffer) {
struct TransactionAckCtx {
scoped_refptr<base::SingleThreadTaskRunner> task_runner;
- base::OnceCallback<void(int64_t)> callback;
+ base::OnceCallback<void(int32_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) {
+void OnTransactionCompletedOnAnyThread(void* ctx, int32_t present_fence) {
auto* ack_ctx = static_cast<TransactionAckCtx*>(ctx);
ack_ctx->task_runner->PostTask(
- FROM_HERE, base::BindOnce(std::move(ack_ctx->callback), present_time_ns));
+ FROM_HERE, base::BindOnce(std::move(ack_ctx->callback), present_fence));
delete ack_ctx;
}
@@ -124,8 +125,8 @@ void GLSurfaceEGLSurfaceControl::CommitPendingTransaction(
base::BindOnce(&GLSurfaceEGLSurfaceControl::OnTransactionAckOnGpuThread,
weak_factory_.GetWeakPtr(), completion_callback,
present_callback, std::move(resources_to_release));
- pending_transaction_->SetCompletedFunc(&OnTransactionCompletedOnAnyThread,
- ack_ctx);
+ pending_transaction_->SetOnCompleteFunc(&OnTransactionCompletedOnAnyThread,
+ ack_ctx);
pending_transaction_->Apply();
pending_transaction_.reset();
@@ -151,8 +152,6 @@ 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();
@@ -193,24 +192,24 @@ bool GLSurfaceEGLSurfaceControl::ScheduleOverlayPlane(
std::move(fence_fd));
}
- if (uninitialized || surface_state.bounds_rect != bounds_rect) {
- surface_state.bounds_rect = bounds_rect;
- pending_transaction_->SetDisplayFrame(surface_state.surface, bounds_rect);
- }
-
- gfx::Rect enclosed_crop_rect;
if (hardware_buffer) {
+ gfx::Rect dst = bounds_rect;
+
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);
+ gfx::Rect src = gfx::ToEnclosedRect(scaled_rect);
+
+ if (uninitialized || surface_state.src != src || surface_state.dst != dst ||
+ surface_state.transform != transform) {
+ surface_state.src = src;
+ surface_state.dst = dst;
+ surface_state.transform = transform;
+ pending_transaction_->SetGeometry(surface_state.surface, src, dst,
+ transform);
}
}
@@ -256,14 +255,27 @@ void GLSurfaceEGLSurfaceControl::OnTransactionAckOnGpuThread(
SwapCompletionCallback completion_callback,
PresentationCallback presentation_callback,
ResourceRefs released_resources,
- int64_t present_time_ns) {
+ int32_t present_fence) {
DCHECK(gpu_task_runner_->BelongsToCurrentThread());
+ // Insert a service wait for this fence to ensure any resource reuse is after
+ // it is signaled.
+ gfx::GpuFenceHandle handle;
+ handle.type = gfx::GpuFenceHandleType::kAndroidNativeFenceSync;
+ handle.native_fd = base::FileDescriptor(present_fence, /*auto_close=*/true);
+ gfx::GpuFence gpu_fence(handle);
+ // TODO(khushalsagar): But what about vulkan?
+ auto gl_fence = GLFence::CreateFromGpuFence(gpu_fence);
+ gl_fence->ServerWait();
+
// The presentation feedback callback must run after swap completion.
completion_callback.Run(gfx::SwapResult::SWAP_ACK, nullptr);
- gfx::PresentationFeedback feedback(
- base::TimeTicks::FromInternalValue(present_time_ns), base::TimeDelta(),
- 0 /* flags */);
+
+ // TODO(khushalsagar): Maintain a queue of fences so we poll to see if they
+ // are signaled every frame, and get a signal timestamp to feed into this
+ // feedback.
+ gfx::PresentationFeedback feedback(base::TimeTicks::Now(), base::TimeDelta(),
+ 0 /* flags */);
presentation_callback.Run(feedback);
released_resources.clear();
}
diff --git a/chromium/ui/gl/gl_surface_egl_surface_control.h b/chromium/ui/gl/gl_surface_egl_surface_control.h
index 7c73fb35326..5542d504235 100644
--- a/chromium/ui/gl/gl_surface_egl_surface_control.h
+++ b/chromium/ui/gl/gl_surface_egl_surface_control.h
@@ -6,6 +6,7 @@
#define UI_GL_GL_SURFACE_EGL_SURFACE_CONTROL_H_
#include <android/native_window.h>
+#include <memory>
#include "base/android/scoped_hardware_buffer_handle.h"
#include "base/memory/weak_ptr.h"
@@ -16,6 +17,10 @@
namespace base {
class SingleThreadTaskRunner;
+
+namespace android {
+class ScopedHardwareBufferFenceSync;
+} // namespace android
} // namespace base
namespace gl {
@@ -75,15 +80,16 @@ class GL_EXPORT GLSurfaceEGLSurfaceControl : public gl::GLSurfaceEGL {
int z_order = 0;
AHardwareBuffer* hardware_buffer = nullptr;
- gfx::Rect bounds_rect;
- gfx::Rect crop_rect;
+ gfx::Rect dst;
+ gfx::Rect src;
+ gfx::OverlayTransform transform = gfx::OVERLAY_TRANSFORM_NONE;
bool opaque = true;
gl::SurfaceControl::Surface surface;
};
- using ResourceRefs =
- std::vector<std::unique_ptr<GLImage::ScopedHardwareBuffer>>;
+ using ResourceRefs = std::vector<
+ std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>>;
void CommitPendingTransaction(
const SwapCompletionCallback& completion_callback,
@@ -94,7 +100,7 @@ class GL_EXPORT GLSurfaceEGLSurfaceControl : public gl::GLSurfaceEGL {
void OnTransactionAckOnGpuThread(SwapCompletionCallback completion_callback,
PresentationCallback presentation_callback,
ResourceRefs released_resources,
- int64_t present_time_ns);
+ int32_t present_fence);
// Holds the surface state changes made since the last call to SwapBuffers.
base::Optional<gl::SurfaceControl::Transaction> pending_transaction_;
diff --git a/chromium/ui/gl/gl_switches.cc b/chromium/ui/gl/gl_switches.cc
index 9626f9bf189..5c5d44addb3 100644
--- a/chromium/ui/gl/gl_switches.cc
+++ b/chromium/ui/gl/gl_switches.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 "base/macros.h"
#include "ui/gl/gl_switches.h"
+#include "base/stl_util.h"
+
namespace gl {
const char kGLImplementationDesktopName[] = "desktop";
@@ -130,7 +131,7 @@ const char* const kGLSwitchesCopiedFromGpuProcessHost[] = {
kDisableDirectCompositionLayers,
};
const int kGLSwitchesCopiedFromGpuProcessHostNumSwitches =
- arraysize(kGLSwitchesCopiedFromGpuProcessHost);
+ base::size(kGLSwitchesCopiedFromGpuProcessHost);
} // namespace switches
diff --git a/chromium/ui/gl/init/BUILD.gn b/chromium/ui/gl/init/BUILD.gn
index b66913884f7..5f5149edfab 100644
--- a/chromium/ui/gl/init/BUILD.gn
+++ b/chromium/ui/gl/init/BUILD.gn
@@ -27,7 +27,7 @@ jumbo_component("init") {
deps = [
"//base",
"//ui/gfx",
- "//ui/gl:gl_features",
+ "//ui/gl:buildflags",
]
public_deps = [
diff --git a/chromium/ui/gl/init/create_gr_gl_interface.cc b/chromium/ui/gl/init/create_gr_gl_interface.cc
index 69512fb9cb6..4c644232e06 100644
--- a/chromium/ui/gl/init/create_gr_gl_interface.cc
+++ b/chromium/ui/gl/init/create_gr_gl_interface.cc
@@ -242,6 +242,8 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fTexBuffer = gl->glTexBufferFn;
functions->fTexBufferRange = gl->glTexBufferRangeFn;
functions->fTexImage2D = bind_slow(gl->glTexImage2DFn, progress_reporter);
+ functions->fTexParameterf = gl->glTexParameterfFn;
+ functions->fTexParameterfv = gl->glTexParameterfvFn;
functions->fTexParameteri = gl->glTexParameteriFn;
functions->fTexParameteriv = gl->glTexParameterivFn;
functions->fTexStorage2D = gl->glTexStorage2DEXTFn;
@@ -523,9 +525,6 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
// functions->fCreateImage = nullptr;
// functions->fDestroyImage = nullptr;
- // GL 4.0 or GL_ARB_sample_shading or ES+GL_OES_sample_shading
- functions->fMinSampleShading = gl->glMinSampleShadingFn;
-
functions->fFenceSync = gl->glFenceSyncFn;
functions->fIsSync = gl->glIsSyncFn;
functions->fClientWaitSync = gl->glClientWaitSyncFn;
diff --git a/chromium/ui/gl/init/gl_factory_mac.cc b/chromium/ui/gl/init/gl_factory_mac.cc
index b764ef94329..d691934d92d 100644
--- a/chromium/ui/gl/init/gl_factory_mac.cc
+++ b/chromium/ui/gl/init/gl_factory_mac.cc
@@ -7,10 +7,10 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/trace_event/trace_event.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context_cgl.h"
#include "ui/gl/gl_context_stub.h"
-#include "ui/gl/gl_features.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_share_group.h"
#include "ui/gl/gl_surface.h"
diff --git a/chromium/ui/gl/init/gl_initializer_android.cc b/chromium/ui/gl/init/gl_initializer_android.cc
index 22660c9207d..83389061452 100644
--- a/chromium/ui/gl/init/gl_initializer_android.cc
+++ b/chromium/ui/gl/init/gl_initializer_android.cc
@@ -9,9 +9,9 @@
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/native_library.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_egl_api_implementation.h"
-#include "ui/gl/gl_features.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_surface_egl.h"
diff --git a/chromium/ui/gl/init/gl_initializer_mac.cc b/chromium/ui/gl/init/gl_initializer_mac.cc
index a89aad20c34..03ad2d5027b 100644
--- a/chromium/ui/gl/init/gl_initializer_mac.cc
+++ b/chromium/ui/gl/init/gl_initializer_mac.cc
@@ -16,9 +16,9 @@
#include "base/native_library.h"
#include "base/path_service.h"
#include "base/threading/thread_restrictions.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
-#include "ui/gl/gl_features.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
diff --git a/chromium/ui/gl/init/gl_initializer_win.cc b/chromium/ui/gl/init/gl_initializer_win.cc
index 54cc8c3ead5..37489a19ede 100644
--- a/chromium/ui/gl/init/gl_initializer_win.cc
+++ b/chromium/ui/gl/init/gl_initializer_win.cc
@@ -17,9 +17,9 @@
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
#include "base/win/windows_version.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_egl_api_implementation.h"
-#include "ui/gl/gl_features.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_surface_wgl.h"
diff --git a/chromium/ui/gl/init/gl_initializer_x11.cc b/chromium/ui/gl/init/gl_initializer_x11.cc
index 0a97a380c08..e3c481b97d8 100644
--- a/chromium/ui/gl/init/gl_initializer_x11.cc
+++ b/chromium/ui/gl/init/gl_initializer_x11.cc
@@ -12,9 +12,9 @@
#include "ui/gfx/switches.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_egl_api_implementation.h"
-#include "ui/gl/gl_features.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_glx_api_implementation.h"
#include "ui/gl/gl_surface_egl.h"
diff --git a/chromium/ui/keyboard/BUILD.gn b/chromium/ui/keyboard/BUILD.gn
index e35899dce89..b3babf71052 100644
--- a/chromium/ui/keyboard/BUILD.gn
+++ b/chromium/ui/keyboard/BUILD.gn
@@ -35,6 +35,8 @@ jumbo_component("keyboard") {
"keyboard_layout_manager.h",
"keyboard_ui.cc",
"keyboard_ui.h",
+ "keyboard_ui_factory.cc",
+ "keyboard_ui_factory.h",
"keyboard_ukm_recorder.cc",
"keyboard_ukm_recorder.h",
"keyboard_util.cc",
@@ -59,7 +61,6 @@ jumbo_component("keyboard") {
":mojom",
":resources",
"//base",
- "//chromeos",
"//services/metrics/public/cpp:ukm_builders",
"//ui/aura",
"//ui/base",
@@ -87,6 +88,10 @@ static_library("test_support") {
sources = [
"test/keyboard_test_util.cc",
"test/keyboard_test_util.h",
+ "test/test_keyboard_layout_delegate.cc",
+ "test/test_keyboard_layout_delegate.h",
+ "test/test_keyboard_ui.cc",
+ "test/test_keyboard_ui.h",
]
deps = [
":keyboard",
diff --git a/chromium/ui/keyboard/DEPS b/chromium/ui/keyboard/DEPS
index 286a31b2fd2..ccc18086d14 100644
--- a/chromium/ui/keyboard/DEPS
+++ b/chromium/ui/keyboard/DEPS
@@ -1,5 +1,4 @@
include_rules = [
- "+chromeos/chromeos_features.h",
"+components/ukm",
"+mojo/public",
"+services/metrics/public/cpp",
diff --git a/chromium/ui/keyboard/keyboard_controller.cc b/chromium/ui/keyboard/keyboard_controller.cc
index b0fe24186ac..87bca7beb34 100644
--- a/chromium/ui/keyboard/keyboard_controller.cc
+++ b/chromium/ui/keyboard/keyboard_controller.cc
@@ -30,7 +30,6 @@
#include "ui/events/base_event_utils.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/path.h"
#include "ui/keyboard/container_floating_behavior.h"
#include "ui/keyboard/container_full_width_behavior.h"
#include "ui/keyboard/container_fullscreen_behavior.h"
@@ -55,18 +54,22 @@ namespace {
// Owned by ash::Shell.
KeyboardController* g_keyboard_controller = nullptr;
-constexpr int kHideKeyboardDelayMs = 100;
+// How long the keyboard stays in WILL_HIDE state before moving to HIDDEN.
+constexpr base::TimeDelta kHideKeyboardDelay =
+ base::TimeDelta::FromMilliseconds(100);
// Reports an error histogram if the keyboard state is lingering in an
// intermediate state for more than 5 seconds.
-constexpr int kReportLingeringStateDelayMs = 5000;
+constexpr base::TimeDelta kReportLingeringStateDelay =
+ base::TimeDelta::FromMilliseconds(5000);
// Delay threshold after the keyboard enters the WILL_HIDE state. If text focus
// is regained during this threshold, the keyboard will show again, even if it
// is an asynchronous event. This is for the benefit of things like login flow
// where the password field may get text focus after an animation that plays
// after the user enters their username.
-constexpr int kTransientBlurThresholdMs = 3500;
+constexpr base::TimeDelta kTransientBlurThreshold =
+ base::TimeDelta::FromMilliseconds(3500);
// State transition diagram (document linked from crbug.com/719905)
bool IsAllowedStateTransition(KeyboardControllerState from,
@@ -254,6 +257,7 @@ void KeyboardController::EnableKeyboard(std::unique_ptr<KeyboardUI> ui,
ui_ = std::move(ui);
DCHECK(ui_);
+ DCHECK(delegate);
layout_delegate_ = delegate;
show_on_keyboard_window_load_ = false;
keyboard_locked_ = false;
@@ -267,6 +271,9 @@ void KeyboardController::EnableKeyboard(std::unique_ptr<KeyboardUI> ui,
for (KeyboardControllerObserver& observer : observer_list_)
observer.OnKeyboardEnabledChanged(true);
+
+ ActivateKeyboardInContainer(
+ layout_delegate_->GetContainerForDefaultDisplay());
}
void KeyboardController::DisableKeyboard() {
@@ -340,6 +347,17 @@ aura::Window* KeyboardController::GetRootWindow() {
return parent_container_ ? parent_container_->GetRootWindow() : nullptr;
}
+void KeyboardController::MoveToParentContainer(aura::Window* parent) {
+ DCHECK(parent);
+ if (parent_container_ == parent)
+ return;
+
+ TRACE_EVENT0("vk", "MoveKeyboardToDisplayInternal");
+
+ DeactivateKeyboard();
+ ActivateKeyboardInContainer(parent);
+}
+
// private
void KeyboardController::NotifyKeyboardBoundsChanging(
const gfx::Rect& new_bounds) {
@@ -616,7 +634,7 @@ void KeyboardController::HideKeyboardImplicitlyBySystem() {
base::BindOnce(&KeyboardController::HideKeyboard,
weak_factory_will_hide_.GetWeakPtr(),
HIDE_REASON_SYSTEM_IMPLICIT),
- base::TimeDelta::FromMilliseconds(kHideKeyboardDelayMs));
+ kHideKeyboardDelay);
}
// private
@@ -676,14 +694,14 @@ void KeyboardController::SetContainerBehaviorInternal(
void KeyboardController::ShowKeyboard(bool lock) {
DVLOG(1) << "ShowKeyboard";
set_keyboard_locked(lock);
- ShowKeyboardInternal(display::Display());
+ ShowKeyboardInternal(layout_delegate_->GetContainerForDefaultDisplay());
}
void KeyboardController::ShowKeyboardInDisplay(
const display::Display& display) {
DVLOG(1) << "ShowKeyboardInDisplay: " << display.id();
set_keyboard_locked(true);
- ShowKeyboardInternal(display);
+ ShowKeyboardInternal(layout_delegate_->GetContainerForDisplay(display));
}
void KeyboardController::LoadKeyboardWindowInBackground() {
@@ -693,7 +711,8 @@ void KeyboardController::LoadKeyboardWindowInBackground() {
if (state_ != KeyboardControllerState::INITIAL)
return;
- PopulateKeyboardContent(display::Display(), false);
+ PopulateKeyboardContent(layout_delegate_->GetContainerForDefaultDisplay(),
+ false);
}
ui::InputMethod* KeyboardController::GetInputMethodForTest() {
@@ -803,12 +822,7 @@ void KeyboardController::OnTextInputStateChanged(
}
void KeyboardController::ShowKeyboardIfWithinTransientBlurThreshold() {
- static const base::TimeDelta kTransientBlurThreshold =
- base::TimeDelta::FromMilliseconds(kTransientBlurThresholdMs);
-
- const base::Time now = base::Time::Now();
- const base::TimeDelta time_since_last_blur = now - time_of_last_blur_;
- if (time_since_last_blur < kTransientBlurThreshold)
+ if (base::Time::Now() - time_of_last_blur_ < kTransientBlurThreshold)
ShowKeyboard(false);
}
@@ -816,18 +830,17 @@ void KeyboardController::OnShowVirtualKeyboardIfEnabled() {
DVLOG(1) << "OnShowVirtualKeyboardIfEnabled: " << IsKeyboardEnableRequested();
// Calling |ShowKeyboardInternal| may move the keyboard to another display.
if (IsKeyboardEnableRequested() && !keyboard_locked_)
- ShowKeyboardInternal(display::Display());
+ ShowKeyboardInternal(layout_delegate_->GetContainerForDefaultDisplay());
}
-void KeyboardController::ShowKeyboardInternal(const display::Display& display) {
+void KeyboardController::ShowKeyboardInternal(aura::Window* target_container) {
MarkKeyboardLoadStarted();
- PopulateKeyboardContent(display, true);
+ PopulateKeyboardContent(target_container, true);
UpdateInputMethodObserver();
}
-void KeyboardController::PopulateKeyboardContent(
- const display::Display& display,
- bool show_keyboard) {
+void KeyboardController::PopulateKeyboardContent(aura::Window* target_container,
+ bool show_keyboard) {
DCHECK(show_keyboard || state_ == KeyboardControllerState::INITIAL);
DVLOG(1) << "PopulateKeyboardContent: " << StateToStr(state_);
@@ -848,12 +861,7 @@ void KeyboardController::PopulateKeyboardContent(
parent_container_->AddChild(keyboard_window);
}
- if (layout_delegate_ != nullptr) {
- if (display.is_valid())
- layout_delegate_->MoveKeyboardToDisplay(display);
- else
- layout_delegate_->MoveKeyboardToTouchableDisplay();
- }
+ MoveToParentContainer(target_container);
aura::Window* keyboard_window = GetKeyboardWindow();
DCHECK(keyboard_window);
@@ -973,7 +981,7 @@ void KeyboardController::ChangeState(KeyboardControllerState state) {
FROM_HERE,
base::BindOnce(&KeyboardController::ReportLingeringState,
weak_factory_report_lingering_state_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kReportLingeringStateDelayMs));
+ kReportLingeringStateDelay);
break;
default:
// Do nothing
@@ -1092,6 +1100,14 @@ bool KeyboardController::IsKeyboardVisible() {
return false;
}
+void KeyboardController::KeyboardContentsLoaded(
+ const base::UnguessableToken& token,
+ const gfx::Size& size) {
+ if (!IsEnabled())
+ return;
+ ui_->KeyboardContentsLoaded(token, size);
+}
+
ui::TextInputClient* KeyboardController::GetTextInputClient() {
return ui_->GetInputMethod()->GetTextInputClient();
}
diff --git a/chromium/ui/keyboard/keyboard_controller.h b/chromium/ui/keyboard/keyboard_controller.h
index 1214f328eee..b60125cae8d 100644
--- a/chromium/ui/keyboard/keyboard_controller.h
+++ b/chromium/ui/keyboard/keyboard_controller.h
@@ -96,16 +96,6 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// Does nothing if the keyboard is already disabled.
void DisableKeyboard();
- // Attach the keyboard window as a child of the given parent window.
- // Can only be called when the keyboard is not activated. |parent| must not
- // have any children.
- void ActivateKeyboardInContainer(aura::Window* parent);
-
- // Detach the keyboard window from its parent container window.
- // Can only be called when the keyboard is activated. Explicitly hides the
- // keyboard if it is currently visible.
- void DeactivateKeyboard();
-
// Returns the keyboard window, or null if the keyboard window has not been
// created yet.
aura::Window* GetKeyboardWindow() const;
@@ -114,6 +104,10 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// null if the keyboard has not been attached to any root window.
aura::Window* GetRootWindow();
+ // Move the keyboard window to a different parent container. |parent| must not
+ // be null.
+ void MoveToParentContainer(aura::Window* parent);
+
// Sets the bounds of the keyboard window.
void SetKeyboardWindowBounds(const gfx::Rect& new_bounds);
@@ -240,6 +234,13 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
bool IsKeyboardVisible();
+ // When the window service is running, this will be called with |token| for
+ // embedding the window and the initial window size.
+ void KeyboardContentsLoaded(const base::UnguessableToken& token,
+ const gfx::Size& size);
+
+ aura::Window* parent_container() { return parent_container_; }
+
ui::InputMethodKeyboardController* input_method_keyboard_controller() {
return input_method_keyboard_controller_.get();
}
@@ -311,9 +312,19 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
void OnTextInputStateChanged(const ui::TextInputClient* client) override;
void OnShowVirtualKeyboardIfEnabled() override;
+ // Attach the keyboard window as a child of the given parent window.
+ // Can only be called when the keyboard is not activated. |parent| must not
+ // have any children.
+ void ActivateKeyboardInContainer(aura::Window* parent);
+
+ // Detach the keyboard window from its parent container window.
+ // Can only be called when the keyboard is activated. Explicitly hides the
+ // keyboard if it is currently visible.
+ void DeactivateKeyboard();
+
// Show virtual keyboard immediately with animation.
- void ShowKeyboardInternal(const display::Display& display);
- void PopulateKeyboardContent(const display::Display& display,
+ void ShowKeyboardInternal(aura::Window* target_container);
+ void PopulateKeyboardContent(aura::Window* target_container,
bool show_keyboard);
// Returns true if keyboard is scheduled to hide.
diff --git a/chromium/ui/keyboard/keyboard_controller_unittest.cc b/chromium/ui/keyboard/keyboard_controller_unittest.cc
index aed5e65c34f..4ab8c573c86 100644
--- a/chromium/ui/keyboard/keyboard_controller_unittest.cc
+++ b/chromium/ui/keyboard/keyboard_controller_unittest.cc
@@ -35,6 +35,8 @@
#include "ui/keyboard/keyboard_ui.h"
#include "ui/keyboard/keyboard_util.h"
#include "ui/keyboard/test/keyboard_test_util.h"
+#include "ui/keyboard/test/test_keyboard_layout_delegate.h"
+#include "ui/keyboard/test/test_keyboard_ui.h"
#include "ui/wm/core/default_activation_client.h"
#if defined(USE_OZONE)
@@ -107,19 +109,6 @@ class KeyboardContainerObserver : public aura::WindowObserver {
DISALLOW_COPY_AND_ASSIGN(KeyboardContainerObserver);
};
-class TestKeyboardLayoutDelegate : public KeyboardLayoutDelegate {
- public:
- TestKeyboardLayoutDelegate() {}
- ~TestKeyboardLayoutDelegate() override {}
-
- // Overridden from keyboard::KeyboardLayoutDelegate
- void MoveKeyboardToDisplay(const display::Display& display) override {}
- void MoveKeyboardToTouchableDisplay() override {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestKeyboardLayoutDelegate);
-};
-
class SetModeCallbackInvocationCounter {
public:
SetModeCallbackInvocationCounter() : weak_factory_invoke_(this) {}
@@ -164,14 +153,13 @@ class KeyboardControllerTest : public aura::test::AuraTestBase,
aura::test::AuraTestBase::SetUp();
new wm::DefaultActivationClient(root_window());
focus_controller_.reset(new TestFocusController(root_window()));
- layout_delegate_.reset(new TestKeyboardLayoutDelegate());
+ layout_delegate_.reset(new TestKeyboardLayoutDelegate(root_window()));
// Force enable the virtual keyboard.
keyboard::SetTouchKeyboardEnabled(true);
controller_.EnableKeyboard(
std::make_unique<TestKeyboardUI>(host()->GetInputMethod()),
layout_delegate_.get());
- controller_.ActivateKeyboardInContainer(root_window());
controller_.AddObserver(this);
}
@@ -695,22 +683,6 @@ TEST_F(KeyboardControllerAnimationTest, ContainerShowWhileHide) {
EXPECT_EQ(1.0, layer->opacity());
}
-TEST_F(KeyboardControllerAnimationTest,
- SetKeyboardWindowBoundsOnDeactivatedKeyboard) {
- // Ensure keyboard ui is populated
- ui::Layer* layer = keyboard_window()->layer();
- ShowKeyboard();
- RunAnimationForLayer(layer);
-
- ASSERT_TRUE(keyboard_window());
-
- controller().DeactivateKeyboard();
-
- // lingering handle to the contents window is adjusted.
- // container_window's LayoutManager should abort silently and not crash.
- keyboard_window()->SetBounds(gfx::Rect());
-}
-
TEST_F(KeyboardControllerTest, DisplayChangeShouldNotifyBoundsChange) {
ui::DummyTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT);
diff --git a/chromium/ui/keyboard/keyboard_layout_delegate.h b/chromium/ui/keyboard/keyboard_layout_delegate.h
index 5e01cde839f..1274e1adcd2 100644
--- a/chromium/ui/keyboard/keyboard_layout_delegate.h
+++ b/chromium/ui/keyboard/keyboard_layout_delegate.h
@@ -13,6 +13,10 @@ namespace display {
class Display;
}
+namespace aura {
+class Window;
+}
+
namespace keyboard {
// A delegate class to control the virtual keyboard layout
@@ -20,11 +24,14 @@ class KEYBOARD_EXPORT KeyboardLayoutDelegate {
public:
virtual ~KeyboardLayoutDelegate() {}
- virtual void MoveKeyboardToDisplay(const display::Display& display) = 0;
+ // Get the container window where the virtual keyboard show appear by default.
+ // Usually, this would be a touchable display with input focus.
+ // This function must not return null.
+ virtual aura::Window* GetContainerForDefaultDisplay() = 0;
- // Move the keyboard to the touchable display which has the input focus, or
- // the first touchable display.
- virtual void MoveKeyboardToTouchableDisplay() = 0;
+ // Get the container window for a particular display. |display| must be valid.
+ virtual aura::Window* GetContainerForDisplay(
+ const display::Display& display) = 0;
};
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_layout_manager.cc b/chromium/ui/keyboard/keyboard_layout_manager.cc
index 7cd0ad6d6c0..cc94c17aef9 100644
--- a/chromium/ui/keyboard/keyboard_layout_manager.cc
+++ b/chromium/ui/keyboard/keyboard_layout_manager.cc
@@ -27,8 +27,14 @@ void KeyboardLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
void KeyboardLayoutManager::SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) {
aura::Window* contents_window = controller_->GetKeyboardWindow();
- if (contents_window != child)
+ if (contents_window != child) {
+ // Let the bounds change to go through for windows other than the virtual
+ // keyboard contents window. This is needed because IME candidate window is
+ // put in VirtualKeyboardContainer managed by this layout manager.
+ if (child->bounds() != requested_bounds)
+ SetChildBoundsDirect(child, requested_bounds);
return;
+ }
TRACE_EVENT0("vk", "KeyboardLayoutSetChildBounds");
diff --git a/chromium/ui/keyboard/keyboard_ui.cc b/chromium/ui/keyboard/keyboard_ui.cc
index 207f9c0c5a7..cda9bfd6877 100644
--- a/chromium/ui/keyboard/keyboard_ui.cc
+++ b/chromium/ui/keyboard/keyboard_ui.cc
@@ -5,10 +5,12 @@
#include "ui/keyboard/keyboard_ui.h"
#include "base/command_line.h"
+#include "base/unguessable_token.h"
#include "ui/aura/window.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ui_base_switches.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/keyboard/keyboard_controller.h"
namespace keyboard {
@@ -33,6 +35,12 @@ void KeyboardUI::HideKeyboardWindow() {
window->Hide();
}
+void KeyboardUI::KeyboardContentsLoaded(const base::UnguessableToken& token,
+ const gfx::Size& size) {
+ NOTREACHED() << "Unexpected call to KeyboardContentsLoaded. Token: " << token
+ << " Size: " << size.ToString();
+}
+
void KeyboardUI::SetController(KeyboardController* controller) {
keyboard_controller_ = controller;
}
diff --git a/chromium/ui/keyboard/keyboard_ui.h b/chromium/ui/keyboard/keyboard_ui.h
index 2fe04dbc982..bb5b648ddd3 100644
--- a/chromium/ui/keyboard/keyboard_ui.h
+++ b/chromium/ui/keyboard/keyboard_ui.h
@@ -13,6 +13,12 @@
namespace aura {
class Window;
}
+namespace base {
+class UnguessableToken;
+}
+namespace gfx {
+class Size;
+}
namespace ui {
class InputMethod;
}
@@ -67,6 +73,11 @@ class KEYBOARD_EXPORT KeyboardUI {
// TODO(https://crbug.com/845780): Change this to accept a callback.
virtual void ReloadKeyboardIfNeeded() = 0;
+ // When the window service is running, this will be called with |token| for
+ // embedding the window and the initial window size.
+ virtual void KeyboardContentsLoaded(const base::UnguessableToken& token,
+ const gfx::Size& size);
+
// |controller| may be null when KeyboardController is being destroyed.
void SetController(KeyboardController* controller);
diff --git a/chromium/ui/keyboard/keyboard_ui_factory.cc b/chromium/ui/keyboard/keyboard_ui_factory.cc
new file mode 100644
index 00000000000..4de381b5b19
--- /dev/null
+++ b/chromium/ui/keyboard/keyboard_ui_factory.cc
@@ -0,0 +1,12 @@
+// 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/keyboard/keyboard_ui_factory.h"
+
+namespace keyboard {
+
+KeyboardUIFactory::KeyboardUIFactory() = default;
+KeyboardUIFactory::~KeyboardUIFactory() = default;
+
+} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_ui_factory.h b/chromium/ui/keyboard/keyboard_ui_factory.h
new file mode 100644
index 00000000000..489be5b06c8
--- /dev/null
+++ b/chromium/ui/keyboard/keyboard_ui_factory.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_KEYBOARD_KEYBOARD_UI_FACTORY_H_
+#define UI_KEYBOARD_KEYBOARD_UI_FACTORY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/keyboard/keyboard_export.h"
+
+namespace keyboard {
+
+class KeyboardUI;
+
+// KeyboardUIFactory is the factory of platform-dependent KeyboardUI.
+class KEYBOARD_EXPORT KeyboardUIFactory {
+ public:
+ KeyboardUIFactory();
+ virtual ~KeyboardUIFactory();
+
+ // Creates a new instance of KeyboardUI.
+ virtual std::unique_ptr<KeyboardUI> CreateKeyboardUI() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(KeyboardUIFactory);
+};
+
+} // namespace keyboard
+
+#endif // UI_KEYBOARD_KEYBOARD_UI_FACTORY_H_
diff --git a/chromium/ui/keyboard/keyboard_util_unittest.cc b/chromium/ui/keyboard/keyboard_util_unittest.cc
index b2165256295..333e0a3ea97 100644
--- a/chromium/ui/keyboard/keyboard_util_unittest.cc
+++ b/chromium/ui/keyboard/keyboard_util_unittest.cc
@@ -6,16 +6,19 @@
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/aura_test_base.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"
#include "ui/keyboard/test/keyboard_test_util.h"
+#include "ui/keyboard/test/test_keyboard_layout_delegate.h"
+#include "ui/keyboard/test/test_keyboard_ui.h"
namespace keyboard {
namespace {
-class KeyboardUtilTest : public testing::Test {
+class KeyboardUtilTest : public aura::test::AuraTestBase {
public:
KeyboardUtilTest() {}
~KeyboardUtilTest() override {}
@@ -51,7 +54,10 @@ class KeyboardUtilTest : public testing::Test {
ClearEnableFlag(mojom::KeyboardEnableFlag::kExtensionEnabled);
}
- void SetUp() override { ResetAllFlags(); }
+ void SetUp() override {
+ aura::test::AuraTestBase::SetUp();
+ ResetAllFlags();
+ }
protected:
void SetEnableFlag(mojom::KeyboardEnableFlag flag) {
@@ -152,6 +158,11 @@ TEST_F(KeyboardUtilTest, UpdateKeyboardConfig) {
TEST_F(KeyboardUtilTest, IsOverscrollEnabled) {
ResetAllFlags();
+ ui::DummyInputMethod input_method;
+ TestKeyboardLayoutDelegate layout_delegate(root_window());
+ keyboard_controller_.EnableKeyboard(
+ std::make_unique<TestKeyboardUI>(&input_method), &layout_delegate);
+
// Return false when keyboard is disabled.
EXPECT_FALSE(keyboard_controller_.IsKeyboardOverscrollEnabled());
@@ -166,18 +177,17 @@ TEST_F(KeyboardUtilTest, IsOverscrollEnabled) {
keyboard_controller_.UpdateKeyboardConfig(config);
EXPECT_FALSE(keyboard_controller_.IsKeyboardOverscrollEnabled());
+ // Set default overscroll flag.
config.overscroll_behavior =
keyboard::mojom::KeyboardOverscrollBehavior::kDefault;
keyboard_controller_.UpdateKeyboardConfig(config);
EXPECT_TRUE(keyboard_controller_.IsKeyboardOverscrollEnabled());
// Set keyboard_locked() to true.
- ui::DummyInputMethod input_method;
- keyboard_controller_.EnableKeyboard(
- std::make_unique<TestKeyboardUI>(&input_method), nullptr);
keyboard_controller_.set_keyboard_locked(true);
EXPECT_TRUE(keyboard_controller_.keyboard_locked());
EXPECT_FALSE(keyboard_controller_.IsKeyboardOverscrollEnabled());
+
keyboard_controller_.DisableKeyboard();
}
diff --git a/chromium/ui/keyboard/resources/keyboard_resource_util.cc b/chromium/ui/keyboard/resources/keyboard_resource_util.cc
index 73aa3fcd74d..79e2f9e5197 100644
--- a/chromium/ui/keyboard/resources/keyboard_resource_util.cc
+++ b/chromium/ui/keyboard/resources/keyboard_resource_util.cc
@@ -5,8 +5,8 @@
#include "ui/keyboard/resources/keyboard_resource_util.h"
#include "base/files/file_path.h"
-#include "base/macros.h"
#include "base/path_service.h"
+#include "base/stl_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/keyboard/grit/keyboard_resources.h"
#include "ui/keyboard/grit/keyboard_resources_map.h"
@@ -93,7 +93,7 @@ const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
{"keyboard/sounds/keypress-standard.wav",
IDR_KEYBOARD_SOUNDS_KEYPRESS_STANDARD},
};
- *size = arraysize(kKeyboardResources);
+ *size = base::size(kKeyboardResources);
return kKeyboardResources;
}
diff --git a/chromium/ui/latency/histograms.h b/chromium/ui/latency/histograms.h
index fba71c12085..3d9545b6207 100644
--- a/chromium/ui/latency/histograms.h
+++ b/chromium/ui/latency/histograms.h
@@ -8,7 +8,7 @@
#include <array>
#include <memory>
-#include "base/macros.h"
+#include "base/stl_util.h"
namespace ui {
@@ -19,7 +19,7 @@ namespace ui {
// estimate.
struct PercentileResults {
static constexpr double kPercentiles[] = {.50, .99};
- static constexpr size_t kCount = arraysize(kPercentiles);
+ static constexpr size_t kCount = base::size(kPercentiles);
double values[kCount]{};
};
diff --git a/chromium/ui/latency/latency_tracker.cc b/chromium/ui/latency/latency_tracker.cc
index 415327b5981..88d834645b4 100644
--- a/chromium/ui/latency/latency_tracker.cc
+++ b/chromium/ui/latency/latency_tracker.cc
@@ -195,15 +195,6 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms(
".TimeToScrollUpdateSwapBegin4",
original_timestamp, gpu_swap_begin_timestamp);
- // This is the same metric as above. But due to a change in rebucketing,
- // UMA pipeline cannot process this for the chirp alerts. Hence adding a
- // newer version the this metric above. TODO(nzolghadr): Remove it in a
- // future milesone like M70.
- UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
- "Event.Latency." + scroll_name + "." + input_modality +
- ".TimeToScrollUpdateSwapBegin2",
- original_timestamp, gpu_swap_begin_timestamp);
-
if (input_modality == "Wheel") {
RecordUmaEventLatencyScrollWheelTimeToScrollUpdateSwapBegin2Histogram(
original_timestamp, gpu_swap_begin_timestamp);
@@ -232,15 +223,6 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms(
".TimeToScrollUpdateSwapBegin4",
original_timestamp, gpu_swap_begin_timestamp);
- // This is the same metric as above. But due to a change in rebucketing,
- // UMA pipeline cannot process this for the chirp alerts. Hence adding a
- // newer version the this metric above. TODO(nzolghadr): Remove it in a
- // future milesone like M70.
- UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
- "Event.Latency." + scroll_name + "." + input_modality +
- ".TimeToScrollUpdateSwapBegin2",
- original_timestamp, gpu_swap_begin_timestamp);
-
if (input_modality == "Wheel") {
RecordUmaEventLatencyScrollWheelTimeToScrollUpdateSwapBegin2Histogram(
original_timestamp, gpu_swap_begin_timestamp);
@@ -455,19 +437,19 @@ void LatencyTracker::CalculateAverageLag(
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_) {
+ // When the |pending_finished_lag_report_| is finished, and the 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 (!pending_finished_lag_report_ &&
+ 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_);
}
}
}
diff --git a/chromium/ui/login/display_manager.js b/chromium/ui/login/display_manager.js
index c32adf58ec4..364798f314b 100644
--- a/chromium/ui/login/display_manager.js
+++ b/chromium/ui/login/display_manager.js
@@ -56,12 +56,9 @@
/** @const */ var ACCELERATOR_DEVICE_REQUISITION = 'device_requisition';
/** @const */ var ACCELERATOR_DEVICE_REQUISITION_REMORA =
'device_requisition_remora';
-/** @const */ var ACCELERATOR_DEVICE_REQUISITION_SHARK =
- 'device_requisition_shark';
/** @const */ var ACCELERATOR_APP_LAUNCH_BAILOUT = 'app_launch_bailout';
/** @const */ var ACCELERATOR_APP_LAUNCH_NETWORK_CONFIG =
'app_launch_network_config';
-/** @const */ var ACCELERATOR_BOOTSTRAPPING_SLAVE = "bootstrapping_slave";
/** @const */ var ACCELERATOR_DEMO_MODE = "demo_mode";
/** @const */ var ACCELERATOR_SEND_FEEDBACK = "send_feedback";
@@ -270,6 +267,12 @@ cr.define('cr.ui.login', function() {
userCount_: 0,
/**
+ * Number of reloadContent() calls since start for testing.
+ * @type {number}
+ */
+ reloadContentNumEvents_: 0,
+
+ /**
* Stored OOBE configuration for newly registered screens.
* @type {!OobeTypes.OobeConfiguration}
*/
@@ -320,6 +323,7 @@ cr.define('cr.ui.login', function() {
/**
* Hides/shows header (Shutdown/Add User/Cancel buttons).
* @param {boolean} hidden Whether header is hidden.
+ * TODO(crbug/914578): talk to the views login shelf through Mojo.
*/
get headerHidden() {
return $('login-header-bar').hidden;
@@ -338,11 +342,8 @@ cr.define('cr.ui.login', function() {
* The header bar should be hidden when views-based shelf is shown.
*/
get showingViewsBasedShelf() {
- var showingViewsLock = loadTimeData.valueExists('showViewsLock') &&
- loadTimeData.getString('showViewsLock') == 'on' &&
- (this.displayType_ == DISPLAY_TYPE.LOCK ||
- this.displayType_ == DISPLAY_TYPE.USER_ADDING);
- return showingViewsLock || this.showingViewsLogin;
+ // TODO: remove this method once webui shelf has been removed.
+ return true;
},
/**
@@ -488,10 +489,6 @@ cr.define('cr.ui.login', function() {
if (this.isOobeUI())
this.showDeviceRequisitionRemoraPrompt_(
'deviceRequisitionRemoraPromptText', 'remora');
- } else if (name == ACCELERATOR_DEVICE_REQUISITION_SHARK) {
- if (this.isOobeUI())
- this.showDeviceRequisitionRemoraPrompt_(
- 'deviceRequisitionSharkPromptText', 'shark');
} else if (name == ACCELERATOR_APP_LAUNCH_BAILOUT) {
if (currentStepId == SCREEN_APP_LAUNCH_SPLASH)
chrome.send('cancelAppLaunch');
@@ -500,8 +497,6 @@ cr.define('cr.ui.login', function() {
} else if (name == ACCELERATOR_APP_LAUNCH_NETWORK_CONFIG) {
if (currentStepId == SCREEN_APP_LAUNCH_SPLASH)
chrome.send('networkConfigRequest');
- } else if (name == ACCELERATOR_BOOTSTRAPPING_SLAVE) {
- chrome.send('setOobeBootstrappingSlave');
} else if (name == ACCELERATOR_DEMO_MODE) {
this.startDemoModeFlow();
} else if (name == ACCELERATOR_SEND_FEEDBACK) {
@@ -873,6 +868,7 @@ cr.define('cr.ui.login', function() {
var currentScreenId = this.screens_[this.currentStep_];
var currentScreen = $(currentScreenId);
this.updateScreenSize(currentScreen);
+ ++this.reloadContentNumEvents_;
},
/**
@@ -933,9 +929,6 @@ cr.define('cr.ui.login', function() {
screen.classList.remove('left');
}
if (this.showingViewsLogin) {
- // Hide the shelf and version info because these should be
- // displayed in views.
- $('login-header-bar').hidden = true;
$('top-header-bar').hidden = true;
}
},
@@ -1065,7 +1058,19 @@ cr.define('cr.ui.login', function() {
*/
toggleClass: function(className, enabled) {
$('oobe').classList.toggle(className, enabled);
- }
+ },
+
+ /**
+ * Notifies the C++ handler in views login that the OOBE signin state has
+ * been updated. This information is primarily used by the login shelf to
+ * update button visibility state.
+ * @param {number} state The state (see SIGNIN_UI_STATE) of the OOBE UI.
+ */
+ setSigninUIState: function(state) {
+ if (Oobe.getInstance().showingViewsLogin)
+ chrome.send('updateSigninUIState', [state]);
+ },
+
};
/**
@@ -1134,7 +1139,6 @@ cr.define('cr.ui.login', function() {
* Disables signin UI.
*/
DisplayManager.disableSigninUI = function() {
- $('login-header-bar').disabled = true;
$('pod-row').disabled = true;
};
@@ -1145,9 +1149,7 @@ cr.define('cr.ui.login', function() {
DisplayManager.showSigninUI = function(opt_email) {
var currentScreenId = Oobe.getInstance().currentScreen.id;
if (currentScreenId == SCREEN_GAIA_SIGNIN)
- $('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
- else if (currentScreenId == SCREEN_ACCOUNT_PICKER)
- $('login-header-bar').signinUIState = SIGNIN_UI_STATE.ACCOUNT_PICKER;
+ Oobe.getInstance().setSigninUIState(SIGNIN_UI_STATE.GAIA_SIGNIN);
chrome.send('showAddUser', [opt_email]);
};
@@ -1162,7 +1164,6 @@ cr.define('cr.ui.login', function() {
if ($(SCREEN_GAIA_SIGNIN))
$(SCREEN_GAIA_SIGNIN)
.reset(currentScreenId == SCREEN_GAIA_SIGNIN, forceOnline);
- $('login-header-bar').disabled = false;
$('pod-row').reset(currentScreenId == SCREEN_ACCOUNT_PICKER);
};
diff --git a/chromium/ui/login/md_screen_container.css b/chromium/ui/login/md_screen_container.css
index 532f4b7b691..7b00e055f22 100644
--- a/chromium/ui/login/md_screen_container.css
+++ b/chromium/ui/login/md_screen_container.css
@@ -116,14 +116,12 @@ html:not([full-screen-dialog]) #oobe.tpm-error-message #inner-container {
#auto-enrollment-check-dot,
#autolaunch-dot,
#confirm-password-dot,
-#controller-pairing-dot,
#debugging-dot,
#device-disabled-dot,
#enrollment-dot,
#error-message-dot,
#fatal-error-dot,
#hid-detection-dot,
-#host-pairing-dot,
#kiosk-enable-dot,
#oauth-enrollment-dot,
#password-changed-dot,
diff --git a/chromium/ui/login/screen_container.css b/chromium/ui/login/screen_container.css
index b60729187fc..472b902a2e9 100644
--- a/chromium/ui/login/screen_container.css
+++ b/chromium/ui/login/screen_container.css
@@ -118,14 +118,12 @@
#auto-enrollment-check-dot,
#autolaunch-dot,
#confirm-password-dot,
-#controller-pairing-dot,
#debugging-dot,
#device-disabled-dot,
#enrollment-dot,
#error-message-dot,
#fatal-error-dot,
#hid-detection-dot,
-#host-pairing-dot,
#kiosk-enable-dot,
#oauth-enrollment-dot,
#password-changed-dot,
diff --git a/chromium/ui/message_center/BUILD.gn b/chromium/ui/message_center/BUILD.gn
index ee5189f31b6..0ea28e028eb 100644
--- a/chromium/ui/message_center/BUILD.gn
+++ b/chromium/ui/message_center/BUILD.gn
@@ -55,12 +55,7 @@ jumbo_component("message_center") {
"//ui/resources",
]
- configs += [
- "//build/config:precompiled_headers",
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- "//build/config/compiler:no_size_t_to_int_warning",
- ]
+ configs += [ "//build/config:precompiled_headers" ]
sources = [
"lock_screen/empty_lock_screen_controller.cc",
"lock_screen/empty_lock_screen_controller.h",
@@ -118,8 +113,6 @@ jumbo_component("message_center") {
"views/notification_control_buttons_view.h",
"views/notification_header_view.cc",
"views/notification_header_view.h",
- "views/notification_view.cc",
- "views/notification_view.h",
"views/notification_view_md.cc",
"views/notification_view_md.h",
"views/padded_button.cc",
@@ -137,6 +130,8 @@ jumbo_component("message_center") {
"views/message_view_context_menu_controller.h",
"views/notification_menu_model.cc",
"views/notification_menu_model.h",
+ "views/notification_view.cc",
+ "views/notification_view.h",
]
}
deps += [
@@ -229,11 +224,13 @@ if (enable_message_center) {
"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" ]
+ sources += [
+ "views/notification_menu_model_unittest.cc",
+ "views/notification_view_unittest.cc",
+ ]
}
deps += [
# Compositor is needed by message_center_view_unittest.cc and for the
diff --git a/chromium/ui/message_center/fake_message_center.cc b/chromium/ui/message_center/fake_message_center.cc
index 2d4213c1d51..abd23cb323a 100644
--- a/chromium/ui/message_center/fake_message_center.cc
+++ b/chromium/ui/message_center/fake_message_center.cc
@@ -89,12 +89,6 @@ void FakeMessageCenter::SetNotificationImage(const std::string& notification_id,
const gfx::Image& image) {
}
-void FakeMessageCenter::SetNotificationButtonIcon(
- const std::string& notification_id,
- int button_index,
- const gfx::Image& image) {
-}
-
void FakeMessageCenter::ClickOnNotification(const std::string& id) {
}
diff --git a/chromium/ui/message_center/fake_message_center.h b/chromium/ui/message_center/fake_message_center.h
index af89a739018..cb884b89102 100644
--- a/chromium/ui/message_center/fake_message_center.h
+++ b/chromium/ui/message_center/fake_message_center.h
@@ -46,9 +46,6 @@ class FakeMessageCenter : public MessageCenter {
void SetNotificationImage(const std::string& notification_id,
const gfx::Image& image) override;
- void SetNotificationButtonIcon(const std::string& notification_id,
- int button_index,
- const gfx::Image& image) override;
void ClickOnNotification(const std::string& id) override;
void ClickOnNotificationButton(const std::string& id,
int button_index) override;
diff --git a/chromium/ui/message_center/message_center.h b/chromium/ui/message_center/message_center.h
index d0a0397d7ca..6f951852559 100644
--- a/chromium/ui/message_center/message_center.h
+++ b/chromium/ui/message_center/message_center.h
@@ -122,11 +122,6 @@ class MESSAGE_CENTER_EXPORT MessageCenter {
virtual void SetNotificationImage(const std::string& notification_id,
const gfx::Image& image) = 0;
- // Sets the image for the icon of the specific action button.
- virtual void SetNotificationButtonIcon(const std::string& notification_id,
- int button_index,
- const gfx::Image& image) = 0;
-
// This should be called by UI classes when a notification is clicked to
// trigger the notification's delegate callback and also update the message
// center observers.
diff --git a/chromium/ui/message_center/message_center_impl.cc b/chromium/ui/message_center/message_center_impl.cc
index a0765b5ae17..3dd44cb8e2e 100644
--- a/chromium/ui/message_center/message_center_impl.cc
+++ b/chromium/ui/message_center/message_center_impl.cc
@@ -308,17 +308,6 @@ void MessageCenterImpl::SetNotificationImage(const std::string& notification_id,
}
}
-void MessageCenterImpl::SetNotificationButtonIcon(
- const std::string& notification_id, int button_index,
- const gfx::Image& image) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (notification_list_->SetNotificationButtonIcon(notification_id,
- button_index, image)) {
- for (auto& observer : observer_list_)
- observer.OnNotificationUpdated(notification_id);
- }
-}
-
void MessageCenterImpl::ClickOnNotification(const std::string& id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (FindVisibleNotificationById(id) == NULL)
diff --git a/chromium/ui/message_center/message_center_impl.h b/chromium/ui/message_center/message_center_impl.h
index 43fc402d77a..e408402bb4d 100644
--- a/chromium/ui/message_center/message_center_impl.h
+++ b/chromium/ui/message_center/message_center_impl.h
@@ -65,9 +65,6 @@ class MessageCenterImpl : public MessageCenter,
const gfx::Image& image) override;
void SetNotificationImage(const std::string& notification_id,
const gfx::Image& image) override;
- void SetNotificationButtonIcon(const std::string& notification_id,
- int button_index,
- const gfx::Image& image) override;
void ClickOnNotification(const std::string& id) override;
void ClickOnNotificationButton(const std::string& id,
int button_index) override;
diff --git a/chromium/ui/message_center/notification_list.cc b/chromium/ui/message_center/notification_list.cc
index 2cadc988b38..bed04243430 100644
--- a/chromium/ui/message_center/notification_list.cc
+++ b/chromium/ui/message_center/notification_list.cc
@@ -157,16 +157,6 @@ bool NotificationList::SetNotificationImage(const std::string& notification_id,
return true;
}
-bool NotificationList::SetNotificationButtonIcon(
- const std::string& notification_id, int button_index,
- const gfx::Image& image) {
- auto iter = GetNotification(notification_id);
- if (iter == notifications_.end())
- return false;
- iter->first->SetButtonIcon(button_index, image);
- return true;
-}
-
bool NotificationList::HasNotificationOfType(const std::string& id,
const NotificationType type) {
auto iter = GetNotification(id);
diff --git a/chromium/ui/message_center/notification_list.h b/chromium/ui/message_center/notification_list.h
index c42bf211f73..bb8a7c50ff2 100644
--- a/chromium/ui/message_center/notification_list.h
+++ b/chromium/ui/message_center/notification_list.h
@@ -107,11 +107,6 @@ class MESSAGE_CENTER_EXPORT NotificationList {
bool SetNotificationImage(const std::string& notification_id,
const gfx::Image& image);
- // Returns true if the notification and button exist and were updated.
- bool SetNotificationButtonIcon(const std::string& notification_id,
- int button_index,
- const gfx::Image& image);
-
// Returns true if |id| matches a notification in the list and that
// notification's type matches the given type.
bool HasNotificationOfType(const std::string& id,
diff --git a/chromium/ui/message_center/public/cpp/notification.h b/chromium/ui/message_center/public/cpp/notification.h
index 7ec1310f2c8..f4afa82b7c0 100644
--- a/chromium/ui/message_center/public/cpp/notification.h
+++ b/chromium/ui/message_center/public/cpp/notification.h
@@ -65,7 +65,8 @@ struct MESSAGE_CENTER_PUBLIC_EXPORT ButtonInfo {
// Icon that should be displayed on the notification button. Optional. On some
// platforms, a mask will be applied to the icon, to match the visual
- // requirements of the notification.
+ // requirements of the notification. As with Android, MD notifications don't
+ // display this icon.
gfx::Image icon;
// The placeholder string that should be displayed in the input field for
diff --git a/chromium/ui/message_center/public/mojo/notification.mojom b/chromium/ui/message_center/public/mojo/notification.mojom
index eb7fba8b453..699d780971c 100644
--- a/chromium/ui/message_center/public/mojo/notification.mojom
+++ b/chromium/ui/message_center/public/mojo/notification.mojom
@@ -42,7 +42,8 @@ struct NotificationItem {
// The fields and their meanings match message_center::ButtonInfo.
struct ButtonInfo {
mojo_base.mojom.String16 title;
- gfx.mojom.ImageSkia? icon;
+ // |icon| intentionally omitted as it's not used on platforms that use mojo
+ // for notifications.
mojo_base.mojom.String16? placeholder;
};
diff --git a/chromium/ui/message_center/public/mojo/notification_struct_traits.cc b/chromium/ui/message_center/public/mojo/notification_struct_traits.cc
index 3be58461182..78cca7ce2bd 100644
--- a/chromium/ui/message_center/public/mojo/notification_struct_traits.cc
+++ b/chromium/ui/message_center/public/mojo/notification_struct_traits.cc
@@ -36,19 +36,9 @@ bool NotificationItemStructTraits::Read(
}
// static
-gfx::ImageSkia ButtonInfoStructTraits::icon(
- const message_center::ButtonInfo& b) {
- return b.icon.AsImageSkia();
-}
-
-// static
bool ButtonInfoStructTraits::Read(
message_center::mojom::ButtonInfoDataView data,
ButtonInfo* out) {
- gfx::ImageSkia icon;
- if (!data.ReadIcon(&icon))
- return false;
- out->icon = gfx::Image(icon);
return data.ReadTitle(&out->title) && data.ReadPlaceholder(&out->placeholder);
}
diff --git a/chromium/ui/message_center/public/mojo/notification_struct_traits.h b/chromium/ui/message_center/public/mojo/notification_struct_traits.h
index e2c68cbbab8..8789c8665e5 100644
--- a/chromium/ui/message_center/public/mojo/notification_struct_traits.h
+++ b/chromium/ui/message_center/public/mojo/notification_struct_traits.h
@@ -147,7 +147,6 @@ struct StructTraits<message_center::mojom::ButtonInfoDataView,
static const base::string16& title(const message_center::ButtonInfo& b) {
return b.title;
}
- static gfx::ImageSkia icon(const message_center::ButtonInfo& b);
static const base::Optional<base::string16>& placeholder(
const message_center::ButtonInfo& b) {
return b.placeholder;
diff --git a/chromium/ui/message_center/vector_icons/notification_snooze_button.icon b/chromium/ui/message_center/vector_icons/notification_snooze_button.icon
index a62c3b42348..da0b7511282 100644
--- a/chromium/ui/message_center/vector_icons/notification_snooze_button.icon
+++ b/chromium/ui/message_center/vector_icons/notification_snooze_button.icon
@@ -5,9 +5,9 @@
// Converted from the svg files attached in http://crbug.com/840497.
CANVAS_DIMENSIONS, 24,
-MOVE_TO, 11.99f, 2,
-ARC_TO, 10, 10, 0, 1, 0, 12, 21.99f,
-ARC_TO, 10, 10, 0, 0, 0, 11.99f, 2,
+MOVE_TO, 12, 2,
+ARC_TO, 10, 10, 0, 1, 0, 12, 22,
+ARC_TO, 10, 10, 0, 0, 0, 12, 2,
CLOSE,
MOVE_TO, 12, 20,
R_ARC_TO, 8, 8, 0, 1, 1, 0, -16,
diff --git a/chromium/ui/message_center/views/message_view.cc b/chromium/ui/message_center/views/message_view.cc
index 86772103554..06de0192de7 100644
--- a/chromium/ui/message_center/views/message_view.cc
+++ b/chromium/ui/message_center/views/message_view.cc
@@ -130,21 +130,6 @@ void MessageView::CloseSwipeControl() {
slide_out_controller_.CloseSwipeControl();
}
-bool MessageView::IsCloseButtonFocused() const {
- auto* control_buttons_view = GetControlButtonsView();
- return control_buttons_view ? control_buttons_view->IsCloseButtonFocused()
- : false;
-}
-
-void MessageView::RequestFocusOnCloseButton() {
- auto* control_buttons_view = GetControlButtonsView();
- if (!control_buttons_view)
- return;
-
- control_buttons_view->RequestFocusOnCloseButton();
- UpdateControlButtonsVisibility();
-}
-
void MessageView::SetExpanded(bool expanded) {
// Not implemented by default.
}
@@ -383,6 +368,7 @@ float MessageView::GetSlideAmount() const {
void MessageView::SetSettingMode(bool setting_mode) {
setting_mode_ = setting_mode;
slide_out_controller_.set_slide_mode(CalculateSlideMode());
+ UpdateControlButtonsVisibility();
}
void MessageView::DisableSlideForcibly(bool disable) {
@@ -407,6 +393,26 @@ void MessageView::OnSnoozeButtonPressed(const ui::Event& event) {
// No default implementation for snooze.
}
+bool MessageView::ShouldShowControlButtons() const {
+#if defined(OS_CHROMEOS)
+ // Users on ChromeOS are used to the Settings and Close buttons not being
+ // visible at all times, but users on other platforms expect them to be
+ // visible.
+ auto* control_buttons_view = GetControlButtonsView();
+ return control_buttons_view &&
+ (control_buttons_view->IsAnyButtonFocused() ||
+ (GetMode() != Mode::SETTING && IsMouseHovered()));
+#else
+ return true;
+#endif
+}
+
+void MessageView::UpdateControlButtonsVisibility() {
+ auto* control_buttons_view = GetControlButtonsView();
+ if (control_buttons_view)
+ control_buttons_view->ShowButtons(ShouldShowControlButtons());
+}
+
void MessageView::SetDrawBackgroundAsActive(bool active) {
background()->SetNativeControlColor(active ? kHoveredButtonBackgroundColor
: kNotificationBackgroundColor);
diff --git a/chromium/ui/message_center/views/message_view.h b/chromium/ui/message_center/views/message_view.h
index a0ea2aef23d..8b59c163bab 100644
--- a/chromium/ui/message_center/views/message_view.h
+++ b/chromium/ui/message_center/views/message_view.h
@@ -83,9 +83,6 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
// Creates a shadow around the notification and changes slide-out behavior.
void SetIsNested();
- bool IsCloseButtonFocused() const;
- void RequestFocusOnCloseButton();
-
virtual NotificationControlButtonsView* GetControlButtonsView() const = 0;
virtual void SetExpanded(bool expanded);
@@ -159,7 +156,7 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
std::string notification_id() const { return notification_id_; }
protected:
- virtual void UpdateControlButtonsVisibility() = 0;
+ virtual void UpdateControlButtonsVisibility();
// Changes the background color and schedules a paint.
virtual void SetDrawBackgroundAsActive(bool active);
@@ -174,6 +171,9 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
// Returns the ideal slide mode by calculating the current status.
SlideOutController::SlideMode CalculateSlideMode() const;
+ // Returns if the control buttons should be shown.
+ bool ShouldShowControlButtons() const;
+
std::string notification_id_;
views::ScrollView* scroller_ = nullptr;
diff --git a/chromium/ui/message_center/views/message_view_factory.cc b/chromium/ui/message_center/views/message_view_factory.cc
index 0ce0d313328..8db23c841cc 100644
--- a/chromium/ui/message_center/views/message_view_factory.cc
+++ b/chromium/ui/message_center/views/message_view_factory.cc
@@ -11,9 +11,12 @@
#include "base/lazy_instance.h"
#include "ui/message_center/public/cpp/features.h"
#include "ui/message_center/public/cpp/notification_types.h"
-#include "ui/message_center/views/notification_view.h"
#include "ui/message_center/views/notification_view_md.h"
+#if !defined(OS_CHROMEOS)
+#include "ui/message_center/views/notification_view.h"
+#endif
+
namespace message_center {
namespace {
@@ -43,11 +46,7 @@ MessageView* MessageViewFactory::Create(const Notification& notification) {
case NOTIFICATION_TYPE_MULTIPLE:
case NOTIFICATION_TYPE_SIMPLE:
case NOTIFICATION_TYPE_PROGRESS:
- // All above roads lead to the generic NotificationView.
- if (base::FeatureList::IsEnabled(message_center::kNewStyleNotifications))
- notification_view = new NotificationViewMD(notification);
- else
- notification_view = new NotificationView(notification);
+ // Rely on default construction after the switch.
break;
case NOTIFICATION_TYPE_CUSTOM:
notification_view = GetCustomNotificationView(notification).release();
@@ -61,8 +60,21 @@ MessageView* MessageViewFactory::Create(const Notification& notification) {
LOG(WARNING) << "Unable to fulfill request for unrecognized or"
<< "unsupported notification type " << notification.type()
<< ". Falling back to simple notification type.";
+ break;
+ }
+
+ if (!notification_view) {
+#if defined(OS_CHROMEOS)
+ notification_view = new NotificationViewMD(notification);
+#else
+ // All above roads lead to the generic NotificationView.
+ if (base::FeatureList::IsEnabled(message_center::kNewStyleNotifications))
+ notification_view = new NotificationViewMD(notification);
+ else
notification_view = new NotificationView(notification);
+#endif
}
+
return notification_view;
}
diff --git a/chromium/ui/message_center/views/notification_control_buttons_view.cc b/chromium/ui/message_center/views/notification_control_buttons_view.cc
index 4619a488ed7..09dff69aa2e 100644
--- a/chromium/ui/message_center/views/notification_control_buttons_view.cc
+++ b/chromium/ui/message_center/views/notification_control_buttons_view.cc
@@ -112,25 +112,18 @@ void NotificationControlButtonsView::ShowSnoozeButton(bool show) {
}
}
-void NotificationControlButtonsView::SetVisible(bool visible) {
+void NotificationControlButtonsView::ShowButtons(bool show) {
DCHECK(layer());
// Manipulate the opacity instead of changing the visibility to keep the tab
// order even when the view is invisible.
- layer()->SetOpacity(visible ? 1. : 0.);
- set_can_process_events_within_subtree(visible);
+ layer()->SetOpacity(show ? 1. : 0.);
+ set_can_process_events_within_subtree(show);
}
-void NotificationControlButtonsView::RequestFocusOnCloseButton() {
- if (close_button_)
- close_button_->RequestFocus();
-}
-
-bool NotificationControlButtonsView::IsCloseButtonFocused() const {
- return close_button_ && close_button_->HasFocus();
-}
-
-bool NotificationControlButtonsView::IsSettingsButtonFocused() const {
- return settings_button_ && settings_button_->HasFocus();
+bool NotificationControlButtonsView::IsAnyButtonFocused() const {
+ return (close_button_ && close_button_->HasFocus()) ||
+ (settings_button_ && settings_button_->HasFocus()) ||
+ (snooze_button_ && snooze_button_->HasFocus());
}
views::Button* NotificationControlButtonsView::close_button() const {
diff --git a/chromium/ui/message_center/views/notification_control_buttons_view.h b/chromium/ui/message_center/views/notification_control_buttons_view.h
index b8b958baeb2..49717d2a9b5 100644
--- a/chromium/ui/message_center/views/notification_control_buttons_view.h
+++ b/chromium/ui/message_center/views/notification_control_buttons_view.h
@@ -42,16 +42,12 @@ class MESSAGE_CENTER_EXPORT NotificationControlButtonsView
// Change the visibility of the settings button. True to show, false to hide.
// Default: hidden.
void ShowSnoozeButton(bool show);
+ // Change the visibility of all buttons. True to show, false to hide.
+ void ShowButtons(bool show);
- // Request the focus on the close button.
- void RequestFocusOnCloseButton();
-
- // Return the focus status of the close button. True if the focus is on the
- // close button, false otherwise.
- bool IsCloseButtonFocused() const;
- // Return the focus status of the settings button. True if the focus is on the
- // close button, false otherwise.
- bool IsSettingsButtonFocused() const;
+ // Return the focus status of any button. True if the focus is on any button,
+ // false otherwise.
+ bool IsAnyButtonFocused() const;
// Methods for retrieving the control buttons directly.
views::Button* close_button() const;
@@ -60,7 +56,6 @@ class MESSAGE_CENTER_EXPORT NotificationControlButtonsView
// views::View
const char* GetClassName() const override;
- void SetVisible(bool visible) override;
// views::ButtonListener
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
diff --git a/chromium/ui/message_center/views/notification_header_view.cc b/chromium/ui/message_center/views/notification_header_view.cc
index 947da04c92c..5bae6eb98b4 100644
--- a/chromium/ui/message_center/views/notification_header_view.cc
+++ b/chromium/ui/message_center/views/notification_header_view.cc
@@ -25,6 +25,8 @@
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/flex_layout_types.h"
#include "ui/views/painter.h"
namespace message_center {
@@ -32,7 +34,9 @@ namespace message_center {
namespace {
constexpr int kHeaderHeight = 32;
-constexpr int kHeaderHorizontalSpacing = 2;
+
+// The padding between controls in the header.
+constexpr gfx::Insets kHeaderSpacing(0, 2, 0, 2);
// The padding outer the header and the control buttons.
constexpr gfx::Insets kHeaderOuterPadding(2, 2, 0, 2);
@@ -42,16 +46,11 @@ constexpr gfx::Insets kHeaderOuterPadding(2, 2, 0, 2);
// Buttom: 6px from the mock.
constexpr gfx::Insets kTextViewPaddingDefault(9, 0, 6, 0);
-// Paddings of the entire header.
-// Left: 14px = 16px (from the mock) - 2px (outer padding).
-// Right: 2px = minimum padding between the control buttons and the header.
-constexpr gfx::Insets kHeaderPadding(0, 14, 0, 2);
-
// Paddings of the app icon (small image).
// Top: 8px = 10px (from the mock) - 2px (outer padding).
// Bottom: 4px from the mock.
// Right: 4px = 6px (from the mock) - kHeaderHorizontalSpacing.
-constexpr gfx::Insets kAppIconPadding(8, 0, 4, 4);
+constexpr gfx::Insets kAppIconPadding(8, 14, 4, 4);
// Size of the expand icon. 8px = 32px - 15px - 9px (values from the mock).
constexpr int kExpandIconSize = 8;
@@ -187,19 +186,22 @@ NotificationHeaderView::NotificationHeaderView(
: views::Button(listener) {
const int kInnerHeaderHeight = kHeaderHeight - kHeaderOuterPadding.height();
- auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
- views::BoxLayout::kHorizontal, kHeaderOuterPadding,
- kHeaderHorizontalSpacing));
- layout->set_cross_axis_alignment(
- views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
+ const views::FlexSpecification kAppNameFlex =
+ views::FlexSpecification::ForSizeRule(
+ views::MinimumFlexSizeRule::kScaleToZero,
+ views::MaximumFlexSizeRule::kPreferred)
+ .WithOrder(1);
- views::View* app_info_container = new views::View();
- auto app_info_layout = std::make_unique<views::BoxLayout>(
- views::BoxLayout::kHorizontal, kHeaderPadding, kHeaderHorizontalSpacing);
- app_info_layout->set_cross_axis_alignment(
- views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
- app_info_container->SetLayoutManager(std::move(app_info_layout));
- AddChildView(app_info_container);
+ const views::FlexSpecification kSpacerFlex =
+ views::FlexSpecification::ForSizeRule(
+ views::MinimumFlexSizeRule::kScaleToZero,
+ views::MaximumFlexSizeRule::kUnbounded)
+ .WithOrder(2);
+
+ auto* layout = SetLayoutManager(std::make_unique<views::FlexLayout>());
+ layout->SetDefaultChildMargins(kHeaderSpacing);
+ layout->SetInteriorMargin(kHeaderOuterPadding);
+ layout->SetCollapseMargins(true);
// App icon view
app_icon_view_ = new views::ImageView();
@@ -208,7 +210,7 @@ NotificationHeaderView::NotificationHeaderView(
app_icon_view_->SetVerticalAlignment(views::ImageView::LEADING);
app_icon_view_->SetHorizontalAlignment(views::ImageView::LEADING);
DCHECK_EQ(kInnerHeaderHeight, app_icon_view_->GetPreferredSize().height());
- app_info_container->AddChildView(app_icon_view_);
+ AddChildView(app_icon_view_);
// Font list for text views.
gfx::FontList font_list = GetHeaderTextFontList();
@@ -217,13 +219,16 @@ NotificationHeaderView::NotificationHeaderView(
// App name view
app_name_view_ = new views::Label(base::string16());
+ // Explicitly disable multiline to support proper text elision for URLs.
+ app_name_view_->SetMultiLine(false);
app_name_view_->SetFontList(font_list);
app_name_view_->SetLineHeight(font_list_height);
app_name_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
app_name_view_->SetEnabledColor(accent_color_);
app_name_view_->SetBorder(views::CreateEmptyBorder(text_view_padding));
DCHECK_EQ(kInnerHeaderHeight, app_name_view_->GetPreferredSize().height());
- app_info_container->AddChildView(app_name_view_);
+ AddChildView(app_name_view_);
+ layout->SetFlexForView(app_name_view_, kAppNameFlex);
// Summary text divider
summary_text_divider_ =
@@ -235,7 +240,7 @@ NotificationHeaderView::NotificationHeaderView(
summary_text_divider_->SetVisible(false);
DCHECK_EQ(kInnerHeaderHeight,
summary_text_divider_->GetPreferredSize().height());
- app_info_container->AddChildView(summary_text_divider_);
+ AddChildView(summary_text_divider_);
// Summary text view
summary_text_view_ = new views::Label(base::string16());
@@ -246,7 +251,7 @@ NotificationHeaderView::NotificationHeaderView(
summary_text_view_->SetVisible(false);
DCHECK_EQ(kInnerHeaderHeight,
summary_text_view_->GetPreferredSize().height());
- app_info_container->AddChildView(summary_text_view_);
+ AddChildView(summary_text_view_);
// Timestamp divider
timestamp_divider_ =
@@ -258,7 +263,7 @@ NotificationHeaderView::NotificationHeaderView(
timestamp_divider_->SetVisible(false);
DCHECK_EQ(kInnerHeaderHeight,
timestamp_divider_->GetPreferredSize().height());
- app_info_container->AddChildView(timestamp_divider_);
+ AddChildView(timestamp_divider_);
// Timestamp view
timestamp_view_ = new views::Label(base::string16());
@@ -268,7 +273,7 @@ NotificationHeaderView::NotificationHeaderView(
timestamp_view_->SetBorder(views::CreateEmptyBorder(text_view_padding));
timestamp_view_->SetVisible(false);
DCHECK_EQ(kInnerHeaderHeight, timestamp_view_->GetPreferredSize().height());
- app_info_container->AddChildView(timestamp_view_);
+ AddChildView(timestamp_view_);
// Expand button view
expand_button_ = new ExpandButton();
@@ -278,13 +283,13 @@ NotificationHeaderView::NotificationHeaderView(
expand_button_->SetHorizontalAlignment(views::ImageView::LEADING);
expand_button_->SetImageSize(gfx::Size(kExpandIconSize, kExpandIconSize));
DCHECK_EQ(kInnerHeaderHeight, expand_button_->GetPreferredSize().height());
- app_info_container->AddChildView(expand_button_);
+ AddChildView(expand_button_);
// Spacer between left-aligned views and right-aligned views
views::View* spacer = new views::View;
spacer->SetPreferredSize(gfx::Size(1, kInnerHeaderHeight));
AddChildView(spacer);
- layout->SetFlexForView(spacer, 1);
+ layout->SetFlexForView(spacer, kSpacerFlex);
// Settings and close buttons view
AddChildView(control_buttons_view);
@@ -305,6 +310,11 @@ void NotificationHeaderView::SetAppName(const base::string16& name) {
app_name_view_->SetText(name);
}
+void NotificationHeaderView::SetAppNameElideBehavior(
+ gfx::ElideBehavior elide_behavior) {
+ app_name_view_->SetElideBehavior(elide_behavior);
+}
+
void NotificationHeaderView::SetProgress(int progress) {
summary_text_view_->SetText(l10n_util::GetStringFUTF16Int(
IDS_MESSAGE_CENTER_NOTIFICATION_PROGRESS_PERCENTAGE, progress));
@@ -397,6 +407,10 @@ std::unique_ptr<views::InkDrop> NotificationHeaderView::CreateInkDrop() {
return std::make_unique<views::InkDropStub>();
}
+const base::string16& NotificationHeaderView::app_name_for_testing() const {
+ return app_name_view_->text();
+}
+
void NotificationHeaderView::UpdateSummaryTextVisibility() {
const bool visible = has_progress_ || has_overflow_indicator_;
summary_text_divider_->SetVisible(visible);
diff --git a/chromium/ui/message_center/views/notification_header_view.h b/chromium/ui/message_center/views/notification_header_view.h
index 72f6caa7e51..edca12dc960 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/gfx/text_constants.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"
@@ -25,6 +26,7 @@ class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button {
views::ButtonListener* listener);
void SetAppIcon(const gfx::ImageSkia& img);
void SetAppName(const base::string16& name);
+ void SetAppNameElideBehavior(gfx::ElideBehavior elide_behavior);
void SetProgress(int progress);
void SetOverflowIndicator(int count);
void SetTimestamp(base::Time past);
@@ -53,6 +55,8 @@ class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button {
SkColor accent_color_for_testing() { return accent_color_; }
+ const base::string16& app_name_for_testing() const;
+
private:
// Update visibility for both |summary_text_view_| and |timestamp_view_|.
void UpdateSummaryTextVisibility();
diff --git a/chromium/ui/message_center/views/notification_view.cc b/chromium/ui/message_center/views/notification_view.cc
index 1bea4a1494e..08f43237f00 100644
--- a/chromium/ui/message_center/views/notification_view.cc
+++ b/chromium/ui/message_center/views/notification_view.cc
@@ -112,11 +112,6 @@ void SetBorderRight(views::View* view, int right) {
class NotificationItemView : public views::View {
public:
explicit NotificationItemView(const NotificationItem& item);
- ~NotificationItemView() override;
-
- // Overridden from views::View:
- void SetVisible(bool visible) override;
-
private:
DISALLOW_COPY_AND_ASSIGN(NotificationItemView);
};
@@ -144,14 +139,6 @@ NotificationItemView::NotificationItemView(const NotificationItem& item) {
SchedulePaint();
}
-NotificationItemView::~NotificationItemView() {}
-
-void NotificationItemView::SetVisible(bool visible) {
- views::View::SetVisible(visible);
- for (int i = 0; i < child_count(); ++i)
- child_at(i)->SetVisible(visible);
-}
-
} // namespace
// NotificationView ////////////////////////////////////////////////////////////
@@ -631,59 +618,21 @@ void NotificationView::UpdateControlButtonsVisibilityWithNotification(
UpdateControlButtonsVisibility();
}
-void NotificationView::UpdateControlButtonsVisibility() {
-#if defined(OS_CHROMEOS)
- // On Chrome OS, the settings button and the close button are shown when:
- // (1) the mouse is hovering on the notification.
- // (2) the focus is on the control buttons.
- const bool target_visibility =
- IsMouseHovered() || control_buttons_view_->IsCloseButtonFocused() ||
- control_buttons_view_->IsSettingsButtonFocused();
-#else
- // On non Chrome OS, the settings button and the close button are always
- // shown.
- const bool target_visibility = true;
-#endif
-
- control_buttons_view_->SetVisible(target_visibility);
-}
-
NotificationControlButtonsView* NotificationView::GetControlButtonsView()
const {
return control_buttons_view_;
}
int NotificationView::GetMessageLineLimit(int title_lines, int width) const {
- // Image notifications require that the image must be kept flush against
- // their icons, but we can allow more text if no image.
int effective_title_lines = std::max(0, title_lines - 1);
- int line_reduction_from_title = (image_view_ ? 1 : 2) * effective_title_lines;
- if (!image_view_) {
- // Title lines are counted as twice as big as message lines for the purpose
- // of this calculation.
- // The effect from the title reduction here should be:
- // * 0 title lines: 5 max lines message.
- // * 1 title line: 5 max lines message.
- // * 2 title lines: 3 max lines message.
- return std::max(0, kMessageExpandedLineLimit - line_reduction_from_title);
- }
-
- int message_line_limit = kMessageCollapsedLineLimit;
-
- // Subtract any lines taken by the context message.
- if (context_message_view_) {
- message_line_limit -= context_message_view_->GetLinesForWidthAndLimit(
- width, kContextMessageLineLimit);
- }
-
+ int line_reduction_from_title = 2 * effective_title_lines;
+ // Title lines are counted as twice as big as message lines for the purpose
+ // of this calculation.
// The effect from the title reduction here should be:
- // * 0 title lines: 2 max lines message + context message.
- // * 1 title line: 2 max lines message + context message.
- // * 2 title lines: 1 max lines message + context message.
- message_line_limit =
- std::max(0, message_line_limit - line_reduction_from_title);
-
- return message_line_limit;
+ // * 0 title lines: 5 max lines message.
+ // * 1 title line: 5 max lines message.
+ // * 2 title lines: 3 max lines message.
+ return std::max(0, kMessageExpandedLineLimit - line_reduction_from_title);
}
int NotificationView::GetMessageHeight(int width, int limit) const {
diff --git a/chromium/ui/message_center/views/notification_view.h b/chromium/ui/message_center/views/notification_view.h
index e58e29e7bc0..e2e5507aea1 100644
--- a/chromium/ui/message_center/views/notification_view.h
+++ b/chromium/ui/message_center/views/notification_view.h
@@ -48,7 +48,6 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
// Overridden from MessageView:
void UpdateWithNotification(const Notification& notification) override;
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
- void UpdateControlButtonsVisibility() override;
NotificationControlButtonsView* GetControlButtonsView() const override;
private:
diff --git a/chromium/ui/message_center/views/notification_view_md.cc b/chromium/ui/message_center/views/notification_view_md.cc
index e6fcbfff3cf..9da43a65e37 100644
--- a/chromium/ui/message_center/views/notification_view_md.cc
+++ b/chromium/ui/message_center/views/notification_view_md.cc
@@ -17,10 +17,12 @@
#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/text_constants.h"
#include "ui/gfx/text_elider.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
@@ -36,6 +38,7 @@
#include "ui/strings/grit/ui_strings.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_mask.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/image_button.h"
@@ -135,16 +138,6 @@ constexpr double kProgressNotificationMessageRatio = 0.7;
// This key/property allows tagging the textfield with its index.
DEFINE_LOCAL_UI_CLASS_PROPERTY_KEY(int, kTextfieldIndexKey, 0U);
-// Users on ChromeOS are used to the Settings and Close buttons not being
-// visible at all times, but users on other platforms expect them to be visible.
-constexpr bool AlwaysShowControlButtons() {
-#if defined(OS_CHROMEOS)
- return false;
-#else
- return true;
-#endif
-}
-
// FontList for the texts except for the header.
gfx::FontList GetTextFontList() {
gfx::Font default_font;
@@ -593,7 +586,7 @@ void NotificationViewMD::Layout() {
// Use vertically larger clip path, so that actions row's top coners will
// not be rounded.
- gfx::Path path;
+ SkPath path;
gfx::Rect bounds = actions_row_->GetLocalBounds();
bounds.set_y(bounds.y() - bounds.height());
bounds.set_height(bounds.height() * 2);
@@ -614,6 +607,13 @@ void NotificationViewMD::Layout() {
}
}
+void NotificationViewMD::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ if (ink_drop_layer_)
+ ink_drop_layer_->SetBounds(gfx::Rect(size()));
+ if (ink_drop_mask_)
+ ink_drop_mask_->layer()->SetBounds(gfx::Rect(size()));
+}
+
void NotificationViewMD::OnFocus() {
MessageView::OnFocus();
ScrollRectToVisible(GetLocalBounds());
@@ -766,6 +766,7 @@ void NotificationViewMD::CreateOrUpdateContextTitleView(
? kNotificationDefaultAccentColor
: notification.accent_color());
header_row_->SetTimestamp(notification.timestamp());
+ header_row_->SetAppNameElideBehavior(gfx::ELIDE_TAIL);
base::string16 app_name = notification.display_source();
if (notification.origin_url().is_valid() &&
@@ -773,6 +774,7 @@ void NotificationViewMD::CreateOrUpdateContextTitleView(
app_name = url_formatter::FormatUrlForSecurityDisplay(
notification.origin_url(),
url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
+ header_row_->SetAppNameElideBehavior(gfx::ELIDE_HEAD);
} else if (app_name.empty() && notification.notifier_id().type ==
NotifierType::SYSTEM_COMPONENT) {
app_name = MessageCenter::Get()->GetSystemNotificationAppName();
@@ -800,7 +802,7 @@ void NotificationViewMD::CreateOrUpdateTitleView(
title_view_ = new views::Label(title);
title_view_->SetFontList(font_list);
- title_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ title_view_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
title_view_->SetEnabledColor(kRegularTextColorMD);
left_content_->AddChildViewAt(title_view_, left_content_count_);
} else {
@@ -967,14 +969,17 @@ void NotificationViewMD::CreateOrUpdateIconView(
void NotificationViewMD::CreateOrUpdateSmallIconView(
const Notification& notification) {
- if (!notification.vector_small_image().is_empty()) {
- header_row_->SetAppIcon(
- gfx::CreateVectorIcon(notification.vector_small_image(),
- kSmallImageSizeMD, notification.accent_color()));
- } else if (!notification.small_image().IsEmpty()) {
- header_row_->SetAppIcon(notification.small_image().AsImageSkia());
- } else {
+ // TODO(knollr): figure out if this has a performance impact and
+ // cache images if so. (crbug.com/768748)
+ gfx::Image masked_small_icon = notification.GenerateMaskedSmallIcon(
+ kSmallImageSizeMD, notification.accent_color() == SK_ColorTRANSPARENT
+ ? message_center::kNotificationDefaultAccentColor
+ : notification.accent_color());
+
+ if (masked_small_icon.IsEmpty()) {
header_row_->ClearAppIcon();
+ } else {
+ header_row_->SetAppIcon(masked_small_icon.AsImageSkia());
}
}
@@ -1242,23 +1247,13 @@ void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) {
MessageCenter::Get()->DisableNotification(notification_id());
}
-// TODO(yoshiki): Move this to the parent class (MessageView) and share the code
-// among NotificationView and ArcNotificationView.
-void NotificationViewMD::UpdateControlButtonsVisibility() {
- const bool target_visibility =
- (AlwaysShowControlButtons() || IsMouseHovered() ||
- control_buttons_view_->IsCloseButtonFocused() ||
- control_buttons_view_->IsSettingsButtonFocused()) &&
- (GetMode() != Mode::SETTING);
-
- control_buttons_view_->SetVisible(target_visibility);
-}
-
void NotificationViewMD::UpdateCornerRadius(int top_radius, int bottom_radius) {
MessageView::UpdateCornerRadius(top_radius, bottom_radius);
action_buttons_row_->SetBackground(views::CreateBackgroundFromPainter(
std::make_unique<NotificationBackgroundPainter>(
0, bottom_radius, kActionsRowBackgroundColor)));
+ top_radius_ = top_radius;
+ bottom_radius_ = bottom_radius;
}
NotificationControlButtonsView* NotificationViewMD::GetControlButtonsView()
@@ -1326,6 +1321,7 @@ void NotificationViewMD::AddBackgroundAnimation(const ui::Event& event) {
}
void NotificationViewMD::RemoveBackgroundAnimation() {
+ SetInkDropMode(InkDropMode::OFF);
AnimateInkDrop(views::InkDropState::HIDDEN, nullptr);
}
@@ -1340,7 +1336,8 @@ void NotificationViewMD::AddInkDropLayer(ui::Layer* ink_drop_layer) {
settings_done_button_->SetPaintToLayer();
settings_done_button_->layer()->SetFillsBoundsOpaquely(false);
ink_drop_container_->AddInkDropLayer(ink_drop_layer);
- InstallInkDropMask(ink_drop_layer);
+ ink_drop_layer_ = ink_drop_layer;
+ InstallNotificationInkDropMask();
}
void NotificationViewMD::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
@@ -1348,18 +1345,38 @@ void NotificationViewMD::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
block_all_button_->DestroyLayer();
dont_block_button_->DestroyLayer();
settings_done_button_->DestroyLayer();
- ResetInkDropMask();
+ ink_drop_mask_.reset();
ink_drop_container_->RemoveInkDropLayer(ink_drop_layer);
GetInkDrop()->RemoveObserver(this);
+ ink_drop_layer_ = nullptr;
}
std::unique_ptr<views::InkDropRipple> NotificationViewMD::CreateInkDropRipple()
const {
return std::make_unique<views::FloodFillInkDropRipple>(
- ink_drop_container_->size(), GetInkDropCenterBasedOnLastEvent(),
+ GetPreferredSize(), GetInkDropCenterBasedOnLastEvent(),
GetInkDropBaseColor(), ink_drop_visible_opacity());
}
+void NotificationViewMD::InstallNotificationInkDropMask() {
+ SkPath path;
+ SkScalar radii[8] = {top_radius_, top_radius_, top_radius_,
+ top_radius_, bottom_radius_, bottom_radius_,
+ bottom_radius_, bottom_radius_};
+ gfx::Rect rect(GetPreferredSize());
+ path.addRoundRect(gfx::RectToSkRect(rect), radii);
+ ink_drop_mask_ = std::make_unique<views::PathInkDropMask>(size(), path);
+ ink_drop_layer_->SetMaskLayer(ink_drop_mask_->layer());
+}
+
+std::unique_ptr<views::InkDropMask> NotificationViewMD::CreateInkDropMask()
+ const {
+ // We don't use this as we need access to the |ink_drop_mask_|.
+ // See crbug.com/915222.
+ NOTREACHED();
+ return nullptr;
+}
+
SkColor NotificationViewMD::GetInkDropBaseColor() const {
// Background of inline settings area.
return SkColorSetRGB(0xEE, 0xEE, 0xEE);
diff --git a/chromium/ui/message_center/views/notification_view_md.h b/chromium/ui/message_center/views/notification_view_md.h
index a954fff6d6f..9ec098ae9a1 100644
--- a/chromium/ui/message_center/views/notification_view_md.h
+++ b/chromium/ui/message_center/views/notification_view_md.h
@@ -173,6 +173,7 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
// Overridden from views::View:
void Layout() override;
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
void OnFocus() override;
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
@@ -184,12 +185,12 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
+ std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
SkColor GetInkDropBaseColor() const override;
// Overridden from MessageView:
void UpdateWithNotification(const Notification& notification) override;
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
- void UpdateControlButtonsVisibility() override;
void UpdateCornerRadius(int top_radius, int bottom_radius) override;
NotificationControlButtonsView* GetControlButtonsView() const override;
bool IsExpanded() const override;
@@ -252,6 +253,9 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
void UpdateViewForExpandedState(bool expanded);
void ToggleInlineSettings(const ui::Event& event);
+ // Initializes |ink_drop_mask_| and sets the mask on |ink_drop_layer_|.
+ void InstallNotificationInkDropMask();
+
views::InkDropContainerView* const ink_drop_container_;
// View containing close and settings buttons
@@ -273,6 +277,15 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
// Describes whether the view should display a hand pointer or not.
bool clickable_;
+ // Corner radii for the InkDropMask.
+ int top_radius_ = 0;
+ int bottom_radius_ = 0;
+
+ // The InkDrop layer and InkDropMask used to update their bounds on
+ // OnBoundsChanged(). See crbug.com/915222.
+ ui::Layer* ink_drop_layer_ = nullptr;
+ std::unique_ptr<views::InkDropMask> ink_drop_mask_;
+
// Container views directly attached to this view.
NotificationHeaderView* header_row_ = nullptr;
views::View* content_row_ = nullptr;
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 bd23045b068..bf98dcaf4db 100644
--- a/chromium/ui/message_center/views/notification_view_md_unittest.cc
+++ b/chromium/ui/message_center/views/notification_view_md_unittest.cc
@@ -256,7 +256,6 @@ const SkBitmap NotificationViewMDTest::CreateBitmap(int width,
std::vector<ButtonInfo> NotificationViewMDTest::CreateButtons(int number) {
ButtonInfo info(base::ASCIIToUTF16("Test button."));
- info.icon = CreateTestImage(4, 4);
return std::vector<ButtonInfo>(number, info);
}
@@ -1040,19 +1039,21 @@ TEST_F(NotificationViewMDTest, InlineSettings) {
generator.ClickLeftButton();
EXPECT_TRUE(notification_view()->settings_row_->visible());
- // By clicking settings button again, it will toggle.
+#if !defined(OS_CHROMEOS)
+ // By clicking settings button again, it will toggle. Skip this on ChromeOS as
+ // the control_buttons_view gets hidden when the inline settings are shown.
generator.ClickLeftButton();
EXPECT_FALSE(notification_view()->settings_row_->visible());
// Show inline settings again.
generator.ClickLeftButton();
EXPECT_TRUE(notification_view()->settings_row_->visible());
+#endif
// Construct a mouse click event 1 pixel inside the done button.
gfx::Point done_cursor_location(1, 1);
- views::View::ConvertPointToTarget(
- notification_view()->control_buttons_view_->settings_button(),
- notification_view(), &done_cursor_location);
+ views::View::ConvertPointToTarget(notification_view()->settings_done_button_,
+ notification_view(), &done_cursor_location);
generator.MoveMouseTo(done_cursor_location);
generator.ClickLeftButton();
diff --git a/chromium/ui/message_center/views/notification_view_unittest.cc b/chromium/ui/message_center/views/notification_view_unittest.cc
index eb7f688f821..c464eff269f 100644
--- a/chromium/ui/message_center/views/notification_view_unittest.cc
+++ b/chromium/ui/message_center/views/notification_view_unittest.cc
@@ -391,18 +391,18 @@ TEST_F(NotificationViewTest, TestLineLimits) {
notification()->set_image(CreateTestImage(2, 2));
notification_view()->UpdateWithNotification(*notification());
- EXPECT_EQ(2, notification_view()->GetMessageLineLimit(0, 360));
- EXPECT_EQ(2, notification_view()->GetMessageLineLimit(1, 360));
- EXPECT_EQ(1, notification_view()->GetMessageLineLimit(2, 360));
+ EXPECT_EQ(5, notification_view()->GetMessageLineLimit(0, 360));
+ EXPECT_EQ(5, notification_view()->GetMessageLineLimit(1, 360));
+ EXPECT_EQ(3, notification_view()->GetMessageLineLimit(2, 360));
notification()->set_context_message(base::ASCIIToUTF16("foo"));
notification_view()->UpdateWithNotification(*notification());
EXPECT_TRUE(notification_view()->context_message_view_ != NULL);
- EXPECT_EQ(1, notification_view()->GetMessageLineLimit(0, 360));
- EXPECT_EQ(1, notification_view()->GetMessageLineLimit(1, 360));
- EXPECT_EQ(0, notification_view()->GetMessageLineLimit(2, 360));
+ EXPECT_EQ(5, notification_view()->GetMessageLineLimit(0, 360));
+ EXPECT_EQ(5, notification_view()->GetMessageLineLimit(1, 360));
+ EXPECT_EQ(3, notification_view()->GetMessageLineLimit(2, 360));
}
TEST_F(NotificationViewTest, TestIconSizing) {
diff --git a/chromium/ui/native_theme/BUILD.gn b/chromium/ui/native_theme/BUILD.gn
index f403d638cad..a2854211fbc 100644
--- a/chromium/ui/native_theme/BUILD.gn
+++ b/chromium/ui/native_theme/BUILD.gn
@@ -8,6 +8,8 @@ import("//testing/test.gni")
jumbo_component("native_theme") {
sources = [
+ "caption_style.cc",
+ "caption_style.h",
"common_theme.cc",
"common_theme.h",
"native_theme.cc",
@@ -37,11 +39,14 @@ jumbo_component("native_theme") {
defines = [ "NATIVE_THEME_IMPLEMENTATION" ]
+ public_deps = [
+ "//skia",
+ ]
+
deps = [
"//base",
"//base/third_party/dynamic_annotations",
"//cc/paint",
- "//skia",
"//ui/base",
"//ui/display",
"//ui/gfx",
@@ -81,6 +86,20 @@ if (is_win) {
}
}
+jumbo_source_set("test_support") {
+ testonly = true
+
+ deps = [
+ ":native_theme",
+ "//base",
+ ]
+
+ sources = [
+ "test_native_theme.cc",
+ "test_native_theme.h",
+ ]
+}
+
test("native_theme_unittests") {
sources = []
diff --git a/chromium/ui/native_theme/OWNERS b/chromium/ui/native_theme/OWNERS
index 77683764fa0..b3faa6e0b26 100644
--- a/chromium/ui/native_theme/OWNERS
+++ b/chromium/ui/native_theme/OWNERS
@@ -1,3 +1,4 @@
+ellyjones@chromium.org
estade@chromium.org
pkasting@chromium.org
diff --git a/chromium/ui/native_theme/caption_style.cc b/chromium/ui/native_theme/caption_style.cc
new file mode 100644
index 00000000000..4a94a073fc0
--- /dev/null
+++ b/chromium/ui/native_theme/caption_style.cc
@@ -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.
+
+#include "ui/native_theme/caption_style.h"
+
+#include "base/json/json_reader.h"
+#include "base/values.h"
+
+namespace ui {
+
+CaptionStyle::CaptionStyle() = default;
+CaptionStyle::CaptionStyle(const CaptionStyle& other) = default;
+CaptionStyle::~CaptionStyle() = default;
+
+// static
+CaptionStyle CaptionStyle::FromSpec(const std::string& spec) {
+ CaptionStyle style;
+ std::unique_ptr<base::Value> dict = base::JSONReader::Read(spec);
+
+ if (!dict || !dict->is_dict())
+ return style;
+
+ if (const std::string* value = dict->FindStringKey("text-color"))
+ style.text_color = *value;
+ if (const std::string* value = dict->FindStringKey("background-color"))
+ style.background_color = *value;
+
+ return style;
+}
+
+} // namespace ui
diff --git a/chromium/ui/native_theme/caption_style.h b/chromium/ui/native_theme/caption_style.h
new file mode 100644
index 00000000000..3ae45b5178d
--- /dev/null
+++ b/chromium/ui/native_theme/caption_style.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_NATIVE_THEME_CAPTION_STYLE_H_
+#define UI_NATIVE_THEME_CAPTION_STYLE_H_
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkScalar.h"
+#include "ui/native_theme/native_theme_export.h"
+
+#include <string>
+
+namespace ui {
+
+struct NATIVE_THEME_EXPORT CaptionStyle {
+ CaptionStyle();
+ CaptionStyle(const CaptionStyle& other);
+ ~CaptionStyle();
+
+ // Returns a CaptionStyle parsed from a specification string, which is a
+ // serialized JSON object whose keys are strings and whose values are of
+ // variable types. See the body of this method for details. This is used to
+ // parse the value of the "--force-caption-style" command-line argument and
+ // for testing.
+ static CaptionStyle FromSpec(const std::string& spec);
+
+ std::string text_color;
+ std::string background_color;
+};
+
+} // namespace ui
+
+#endif
diff --git a/chromium/ui/native_theme/common_theme.cc b/chromium/ui/native_theme/common_theme.cc
index 74c8e5cb48e..120aa3abb15 100644
--- a/chromium/ui/native_theme/common_theme.cc
+++ b/chromium/ui/native_theme/common_theme.cc
@@ -18,22 +18,6 @@ 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()) {
@@ -45,10 +29,68 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
case NativeTheme::kColorId_SeparatorColor:
case NativeTheme::kColorId_UnfocusedBorderColor:
case NativeTheme::kColorId_TabBottomBorder:
- return SK_ColorBLACK;
+ return base_theme->SystemDarkModeEnabled() ? SK_ColorWHITE
+ : SK_ColorBLACK;
case NativeTheme::kColorId_FocusedBorderColor:
case NativeTheme::kColorId_ProminentButtonColor:
- return gfx::kGoogleBlue900;
+ return base_theme->SystemDarkModeEnabled() ? gfx::kGoogleBlue100
+ : gfx::kGoogleBlue900;
+ default:
+ break;
+ }
+ }
+
+ if (base_theme->SystemDarkModeEnabled()) {
+ switch (color_id) {
+ case NativeTheme::kColorId_LabelEnabledColor:
+ case NativeTheme::kColorId_TextfieldDefaultColor:
+ case NativeTheme::kColorId_SelectedMenuItemForegroundColor:
+ return gfx::kGoogleGrey200;
+ case NativeTheme::kColorId_UnfocusedBorderColor:
+ return SK_ColorTRANSPARENT;
+ case NativeTheme::kColorId_ButtonEnabledColor:
+ case NativeTheme::kColorId_ButtonHoverColor:
+ return gfx::kGoogleGrey200;
+ case NativeTheme::kColorId_FocusedMenuItemBackgroundColor:
+ case NativeTheme::kColorId_FocusedHighlightedMenuItemBackgroundColor:
+ return SkColorSetA(SK_ColorWHITE, 0x20);
+ case NativeTheme::kColorId_MenuBackgroundColor:
+ case NativeTheme::kColorId_BubbleBackground:
+ case NativeTheme::kColorId_DialogBackground:
+ return color_utils::AlphaBlend(SK_ColorWHITE, gfx::kGoogleGrey900,
+ 0.04f);
+ case NativeTheme::kColorId_ProminentButtonColor:
+ return gfx::kGoogleBlue300;
+ case NativeTheme::kColorId_TextOnProminentButtonColor:
+ return gfx::kGoogleGrey900;
+ case NativeTheme::kColorId_ProminentButtonDisabledColor:
+ return gfx::kGoogleGrey800;
+ case NativeTheme::kColorId_ButtonBorderColor:
+ return gfx::kGoogleGrey700;
+ case NativeTheme::kColorId_TextfieldSelectionColor:
+ case NativeTheme::kColorId_LabelTextSelectionColor:
+ case NativeTheme::kColorId_TreeSelectionBackgroundFocused:
+ case NativeTheme::kColorId_TreeSelectionBackgroundUnfocused:
+ return color_utils::AlphaBlend(
+ SK_ColorWHITE,
+ GetAuraColor(
+ NativeTheme::kColorId_LabelTextSelectionBackgroundFocused,
+ base_theme),
+ SkAlpha{0xDD});
+ case NativeTheme::kColorId_MenuSeparatorColor:
+ case NativeTheme::kColorId_SeparatorColor:
+ return SkColorSetA(gfx::kGoogleGrey800, 0xCC);
+ case NativeTheme::kColorId_TextfieldDefaultBackground:
+ return SkColorSetA(SK_ColorBLACK, 0x4D);
+ case NativeTheme::kColorId_LinkEnabled:
+ case NativeTheme::kColorId_LinkPressed:
+ return gfx::kGoogleBlue300;
+ case NativeTheme::kColorId_HighlightedMenuItemBackgroundColor:
+ return SkColorSetRGB(0x32, 0x36, 0x39);
+ case NativeTheme::kColorId_TreeBackground:
+ return gfx::kGoogleGrey800;
+ case NativeTheme::kColorId_TreeText:
+ return SkColorSetA(SK_ColorWHITE, 0xDD);
default:
break;
}
@@ -85,7 +127,7 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
}
// Shared constant for disabled text.
- constexpr SkColor kDisabledTextColor = SkColorSetRGB(0xA1, 0xA1, 0x92);
+ constexpr SkColor kDisabledTextColor = gfx::kGoogleGrey600;
// Buttons:
constexpr SkColor kButtonEnabledColor = gfx::kChromeIconGrey;
@@ -93,7 +135,7 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
constexpr SkColor kTextSelectionBackgroundFocused =
SkColorSetARGB(0x54, 0x60, 0xA8, 0xEB);
static const SkColor kTextSelectionColor = color_utils::AlphaBlend(
- SK_ColorBLACK, kTextSelectionBackgroundFocused, 0xdd);
+ SK_ColorBLACK, kTextSelectionBackgroundFocused, SkAlpha{0xDD});
switch (color_id) {
// Dialogs
@@ -106,6 +148,8 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
case NativeTheme::kColorId_ButtonEnabledColor:
case NativeTheme::kColorId_ButtonHoverColor:
return kButtonEnabledColor;
+ case NativeTheme::kColorId_ProminentButtonFocusedColor:
+ return gfx::kGoogleBlue400;
case NativeTheme::kColorId_ProminentButtonColor:
return gfx::kGoogleBlue500;
case NativeTheme::kColorId_TextOnProminentButtonColor:
@@ -114,6 +158,10 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
return SK_ColorTRANSPARENT;
case NativeTheme::kColorId_ButtonDisabledColor:
return kDisabledTextColor;
+ case NativeTheme::kColorId_ProminentButtonDisabledColor:
+ return gfx::kGoogleGrey100;
+ case NativeTheme::kColorId_ButtonBorderColor:
+ return gfx::kGoogleGrey300;
// MenuItem
case NativeTheme::kColorId_TouchableMenuItemLabelColor:
@@ -126,11 +174,11 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
case NativeTheme::kColorId_MenuBorderColor:
return SkColorSetRGB(0xBA, 0xBA, 0xBA);
case NativeTheme::kColorId_MenuSeparatorColor:
- return SkColorSetRGB(0xE9, 0xE9, 0xE9);
+ return gfx::kGoogleGrey200;
case NativeTheme::kColorId_MenuBackgroundColor:
return SK_ColorWHITE;
case NativeTheme::kColorId_FocusedMenuItemBackgroundColor:
- return SkColorSetA(SK_ColorBLACK, 0x14);
+ return gfx::kGoogleGrey200;
case NativeTheme::kColorId_DisabledMenuItemForegroundColor:
return kDisabledTextColor;
case NativeTheme::kColorId_MenuItemMinorTextColor:
@@ -141,6 +189,8 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
return gfx::kGoogleGrey900;
case NativeTheme::kColorId_FocusedHighlightedMenuItemBackgroundColor:
return gfx::kGoogleGrey200;
+ case NativeTheme::kColorId_MenuItemAlertBackgroundColor:
+ return SkColorSetA(gfx::kGoogleBlue600, 0x1A);
// Label
case NativeTheme::kColorId_LabelEnabledColor:
diff --git a/chromium/ui/native_theme/native_theme.cc b/chromium/ui/native_theme/native_theme.cc
index d14f8051798..57272fc2ebc 100644
--- a/chromium/ui/native_theme/native_theme.cc
+++ b/chromium/ui/native_theme/native_theme.cc
@@ -54,4 +54,12 @@ bool NativeTheme::SystemDarkModeEnabled() const {
switches::kForceDarkMode);
}
+CaptionStyle NativeTheme::GetSystemCaptionStyle() const {
+ std::string style =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kForceCaptionStyle);
+
+ return CaptionStyle::FromSpec(style);
+}
+
} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme.h b/chromium/ui/native_theme/native_theme.h
index 2796e42e1e9..796fe26a2ac 100644
--- a/chromium/ui/native_theme/native_theme.h
+++ b/chromium/ui/native_theme/native_theme.h
@@ -14,6 +14,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/native_theme/caption_style.h"
#include "ui/native_theme/native_theme_export.h"
namespace gfx {
@@ -304,7 +305,10 @@ class NATIVE_THEME_EXPORT NativeTheme {
kColorId_ButtonHoverColor,
kColorId_ButtonPressedShade,
kColorId_ProminentButtonColor,
+ kColorId_ProminentButtonFocusedColor,
+ kColorId_ProminentButtonDisabledColor,
kColorId_TextOnProminentButtonColor,
+ kColorId_ButtonBorderColor,
// MenuItem
kColorId_TouchableMenuItemLabelColor,
kColorId_ActionableSubmenuVerticalSeparatorColor,
@@ -319,6 +323,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
kColorId_HighlightedMenuItemBackgroundColor,
kColorId_HighlightedMenuItemForegroundColor,
kColorId_FocusedHighlightedMenuItemBackgroundColor,
+ kColorId_MenuItemAlertBackgroundColor,
// Label
kColorId_LabelEnabledColor,
kColorId_LabelDisabledColor,
@@ -409,6 +414,9 @@ class NATIVE_THEME_EXPORT NativeTheme {
// Whether OS-level dark mode (as in macOS Mojave or Windows 10) is enabled.
virtual bool SystemDarkModeEnabled() const;
+ // Returns the system's caption style.
+ virtual CaptionStyle GetSystemCaptionStyle() 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 a6cb8b47139..e30452b4114 100644
--- a/chromium/ui/native_theme/native_theme_aura.cc
+++ b/chromium/ui/native_theme/native_theme_aura.cc
@@ -12,6 +12,7 @@
#include "build/build_config.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/layout.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/canvas.h"
@@ -20,7 +21,6 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/skia_util.h"
#include "ui/native_theme/common_theme.h"
#include "ui/native_theme/native_theme_features.h"
@@ -114,7 +114,7 @@ void NativeThemeAura::PaintMenuPopupBackground(
flags.setAntiAlias(true);
flags.setColor(color);
- gfx::Path path;
+ SkPath path;
SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()),
SkIntToScalar(size.height()));
SkScalar radius = SkIntToScalar(menu_background.corner_radius);
diff --git a/chromium/ui/native_theme/native_theme_dark_aura.cc b/chromium/ui/native_theme/native_theme_dark_aura.cc
index 712fc0d96ce..54bbee095eb 100644
--- a/chromium/ui/native_theme/native_theme_dark_aura.cc
+++ b/chromium/ui/native_theme/native_theme_dark_aura.cc
@@ -27,6 +27,8 @@ SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id) const {
// Button
case kColorId_ButtonEnabledColor:
return SK_ColorWHITE;
+ case kColorId_ProminentButtonFocusedColor:
+ return gfx::kGoogleBlue500;
case kColorId_ProminentButtonColor:
return gfx::kGoogleBlue600;
@@ -76,6 +78,8 @@ SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id) const {
case kColorId_TextOnProminentButtonColor:
case kColorId_ButtonPressedShade:
case kColorId_ResultsTableHoveredBackground:
+ case kColorId_ProminentButtonDisabledColor:
+ case kColorId_ButtonBorderColor:
return NativeThemeAura::GetSystemColor(color_id);
// Any other color is not defined and shouldn't be used in a dark theme.
@@ -95,6 +99,7 @@ SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id) const {
case kColorId_HighlightedMenuItemBackgroundColor:
case kColorId_HighlightedMenuItemForegroundColor:
case kColorId_FocusedHighlightedMenuItemBackgroundColor:
+ case kColorId_MenuItemAlertBackgroundColor:
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 58bd97b4b81..0076b510328 100644
--- a/chromium/ui/native_theme/native_theme_mac.h
+++ b/chromium/ui/native_theme/native_theme_mac.h
@@ -5,11 +5,14 @@
#ifndef UI_NATIVE_THEME_NATIVE_THEME_MAC_H_
#define UI_NATIVE_THEME_NATIVE_THEME_MAC_H_
+#include "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#include "base/no_destructor.h"
#include "ui/native_theme/native_theme_base.h"
#include "ui/native_theme/native_theme_export.h"
+@class NativeThemeEffectiveAppearanceObserver;
+
namespace ui {
// Mac implementation of native theme support.
@@ -33,6 +36,13 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase {
// an appropriate gray.
static SkColor ApplySystemControlTint(SkColor color);
+ // If the system is not running Mojave, or not forcing dark/light mode, do
+ // nothing. Otherwise, set the correct appearance on NSApp, adjusting for High
+ // Contrast if necessary.
+ // TODO(lgrey): Remove this when we're no longer suppressing dark mode by
+ // default.
+ static void MaybeUpdateBrowserAppearance();
+
// Overridden from NativeTheme:
SkColor GetSystemColor(ColorId color_id) const override;
@@ -74,6 +84,10 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase {
void PaintSelectedMenuItem(cc::PaintCanvas* canvas,
const gfx::Rect& rect) const;
+ base::scoped_nsobject<NativeThemeEffectiveAppearanceObserver>
+ appearance_observer_;
+ id high_contrast_notification_token_;
+
DISALLOW_COPY_AND_ASSIGN(NativeThemeMac);
};
diff --git a/chromium/ui/native_theme/native_theme_mac.mm b/chromium/ui/native_theme/native_theme_mac.mm
index 4f48f0c4178..de3389fac98 100644
--- a/chromium/ui/native_theme/native_theme_mac.mm
+++ b/chromium/ui/native_theme/native_theme_mac.mm
@@ -7,10 +7,13 @@
#import <Cocoa/Cocoa.h>
#include <stddef.h>
+#include "base/command_line.h"
#include "base/mac/mac_util.h"
#include "base/mac/sdk_forward_declarations.h"
#include "base/macros.h"
#import "skia/ext/skia_utils_mac.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/base/ui_base_switches.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/skia_util.h"
@@ -22,12 +25,42 @@
@end
-namespace {
+// Helper object to respond to light mode/dark mode changeovers.
+@interface NativeThemeEffectiveAppearanceObserver : NSObject
+@end
-const SkColor kMenuPopupBackgroundColor = SK_ColorWHITE;
-// TODO(crbug.com/893598): Finalize dark mode color.
-const SkColor kMenuPopupBackgroundColorDarkMode =
- SkColorSetRGB(0x2B, 0x2B, 0x2B);
+@implementation NativeThemeEffectiveAppearanceObserver
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ if (@available(macOS 10.14, *)) {
+ [NSApp addObserver:self
+ forKeyPath:@"effectiveAppearance"
+ options:0
+ context:nullptr];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ if (@available(macOS 10.14, *)) {
+ [NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
+ }
+ [super dealloc];
+}
+
+- (void)observeValueForKeyPath:(NSString*)forKeyPath
+ ofObject:(id)object
+ change:(NSDictionary*)change
+ context:(void*)context {
+ ui::NativeTheme::GetInstanceForNativeUi()->NotifyObservers();
+}
+
+@end
+
+namespace {
// Helper to make indexing an array by an enum class easier.
template <class KEY, class VALUE>
@@ -113,7 +146,42 @@ SkColor NativeThemeMac::ApplySystemControlTint(SkColor color) {
return color;
}
+// static
+void NativeThemeMac::MaybeUpdateBrowserAppearance() {
+ if (@available(macOS 10.14, *)) {
+ if (!base::FeatureList::IsEnabled(features::kDarkMode)) {
+ NSAppearanceName new_appearance_name =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kForceDarkMode)
+ ? NSAppearanceNameDarkAqua
+ : NSAppearanceNameAqua;
+
+ [NSApp setAppearance:[NSAppearance appearanceNamed:new_appearance_name]];
+ }
+ }
+}
+
SkColor NativeThemeMac::GetSystemColor(ColorId color_id) const {
+ // Empirically, currentAppearance is incorrect when switching
+ // appearances. It's unclear exactly why right now, so work
+ // around it for the time being by resynchronizing.
+ if (@available(macOS 10.14, *)) {
+ NSAppearance* effective_appearance = [NSApp effectiveAppearance];
+ if (![effective_appearance isEqual:[NSAppearance currentAppearance]]) {
+ [NSAppearance setCurrentAppearance:effective_appearance];
+ }
+ }
+
+ if (UsesHighContrastColors()) {
+ switch (color_id) {
+ case kColorId_SelectedMenuItemForegroundColor:
+ return SystemDarkModeEnabled() ? SK_ColorBLACK : SK_ColorWHITE;
+ case kColorId_FocusedMenuItemBackgroundColor:
+ return SystemDarkModeEnabled() ? SK_ColorLTGRAY : SK_ColorDKGRAY;
+ default:
+ break;
+ }
+ }
// Even with --secondary-ui-md, menus use the platform colors and styling, and
// Mac has a couple of specific color overrides, documented below.
switch (color_id) {
@@ -121,21 +189,11 @@ SkColor NativeThemeMac::GetSystemColor(ColorId color_id) const {
return NSSystemColorToSkColor([NSColor controlTextColor]);
case kColorId_DisabledMenuItemForegroundColor:
return NSSystemColorToSkColor([NSColor disabledControlTextColor]);
- case kColorId_SelectedMenuItemForegroundColor:
- return UsesHighContrastColors() ? SK_ColorWHITE : SK_ColorBLACK;
- case kColorId_FocusedMenuItemBackgroundColor:
- return UsesHighContrastColors() ? SK_ColorDKGRAY : gfx::kGoogleGrey200;
- case kColorId_MenuBackgroundColor:
- case kColorId_BubbleBackground:
- case kColorId_DialogBackground:
- return SystemDarkModeEnabled() ? kMenuPopupBackgroundColorDarkMode
- : kMenuPopupBackgroundColor;
case kColorId_MenuSeparatorColor:
- return UsesHighContrastColors() ? SK_ColorBLACK
- : SkColorSetA(SK_ColorBLACK, 0x26);
+ return SystemDarkModeEnabled() ? SkColorSetA(gfx::kGoogleGrey800, 0xCC)
+ : SkColorSetA(SK_ColorBLACK, 0x26);
case kColorId_MenuBorderColor:
- return UsesHighContrastColors() ? SK_ColorBLACK
- : SkColorSetA(SK_ColorBLACK, 0x60);
+ return SkColorSetA(SK_ColorBLACK, 0x60);
// Mac has a different "pressed button" styling because it doesn't use
// ripples.
@@ -214,9 +272,26 @@ bool NativeThemeMac::SystemDarkModeEnabled() const {
}
NativeThemeMac::NativeThemeMac() {
+ if (base::FeatureList::IsEnabled(features::kDarkMode)) {
+ appearance_observer_.reset(
+ [[NativeThemeEffectiveAppearanceObserver alloc] init]);
+ }
+ if (@available(macOS 10.10, *)) {
+ high_contrast_notification_token_ = [[[NSWorkspace sharedWorkspace]
+ notificationCenter]
+ addObserverForName:
+ NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
+ object:nil
+ queue:nil
+ usingBlock:^(NSNotification* notification) {
+ ui::NativeTheme::GetInstanceForNativeUi()->NotifyObservers();
+ }];
+ }
}
NativeThemeMac::~NativeThemeMac() {
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:high_contrast_notification_token_];
}
void NativeThemeMac::PaintSelectedMenuItem(cc::PaintCanvas* canvas,
diff --git a/chromium/ui/native_theme/native_theme_win.cc b/chromium/ui/native_theme/native_theme_win.cc
index c0344b4337d..932abb6b7c4 100644
--- a/chromium/ui/native_theme/native_theme_win.cc
+++ b/chromium/ui/native_theme/native_theme_win.cc
@@ -10,9 +10,11 @@
#include <vsstyle.h>
#include <vssym32.h>
+#include "base/bind.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_select_object.h"
@@ -28,6 +30,7 @@
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/color_palette.h"
@@ -253,6 +256,19 @@ NativeThemeWin::NativeThemeWin()
close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
GetProcAddress(theme_dll_, "CloseThemeData"));
}
+ if (base::FeatureList::IsEnabled(features::kDarkMode)) {
+ // Dark Mode currently targets UWP apps, which means Win32 apps need to use
+ // alternate, less reliable means of detecting the state. The following
+ // can break in future Windows versions.
+ bool key_open_succeeded =
+ hkcu_themes_regkey_.Open(
+ HKEY_CURRENT_USER,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\"
+ L"Themes\\Personalize",
+ KEY_READ | KEY_NOTIFY) == ERROR_SUCCESS;
+ if (key_open_succeeded)
+ RegisterThemeRegkeyObserver();
+ }
memset(theme_handles_, 0, sizeof(theme_handles_));
// Initialize the cached system colors.
@@ -516,12 +532,12 @@ SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
return system_colors_[COLOR_WINDOW];
case kColorId_ResultsTableHoveredBackground:
return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHT],
- system_colors_[COLOR_WINDOW], 0x40);
+ system_colors_[COLOR_WINDOW], 0.25f);
case kColorId_ResultsTableNormalText:
return system_colors_[COLOR_WINDOWTEXT];
case kColorId_ResultsTableDimmedText:
return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT],
- system_colors_[COLOR_WINDOW], 0x80);
+ system_colors_[COLOR_WINDOW], 0.5f);
default:
break;
}
@@ -562,6 +578,17 @@ bool NativeThemeWin::UsesHighContrastColors() const {
return force_enabled || IsUsingHighContrastThemeInternal();
}
+bool NativeThemeWin::SystemDarkModeEnabled() const {
+ bool fDarkModeEnabled = false;
+ if (hkcu_themes_regkey_.Valid()) {
+ DWORD apps_use_light_theme = 1;
+ hkcu_themes_regkey_.ReadValueDW(L"AppsUseLightTheme",
+ &apps_use_light_theme);
+ fDarkModeEnabled = (apps_use_light_theme == 0);
+ }
+ return fDarkModeEnabled || NativeTheme::SystemDarkModeEnabled();
+}
+
void NativeThemeWin::PaintIndirect(cc::PaintCanvas* destination_canvas,
Part part,
State state,
@@ -980,7 +1007,7 @@ HRESULT NativeThemeWin::PaintScrollbarArrow(
if (handle && draw_theme_) {
int index = part - kScrollbarDownArrow;
DCHECK_GE(index, 0);
- DCHECK_LT(static_cast<size_t>(index), arraysize(state_id_matrix));
+ DCHECK_LT(static_cast<size_t>(index), base::size(state_id_matrix));
int state_id = state_id_matrix[index][state];
// Hovering means that the cursor is over the scroolbar, but not over the
@@ -1890,4 +1917,16 @@ HANDLE NativeThemeWin::GetThemeHandle(ThemeName theme_name) const {
return handle;
}
+void NativeThemeWin::RegisterThemeRegkeyObserver() {
+ DCHECK(hkcu_themes_regkey_.Valid());
+ hkcu_themes_regkey_.StartWatching(base::BindOnce(
+ [](NativeThemeWin* native_theme) {
+ native_theme->NotifyObservers();
+ // RegKey::StartWatching only provides one notification. Reregistration
+ // is required to get future notifications.
+ native_theme->RegisterThemeRegkeyObserver();
+ },
+ base::Unretained(this)));
+}
+
} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_win.h b/chromium/ui/native_theme/native_theme_win.h
index 9ee7350fa64..cdc21571aa2 100644
--- a/chromium/ui/native_theme/native_theme_win.h
+++ b/chromium/ui/native_theme/native_theme_win.h
@@ -19,6 +19,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/no_destructor.h"
+#include "base/win/registry.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/sys_color_change_listener.h"
@@ -80,6 +81,7 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme,
gfx::Size GetNinePatchCanvasSize(Part part) const override;
gfx::Rect GetNinePatchAperture(Part part) const override;
bool UsesHighContrastColors() const override;
+ bool SystemDarkModeEnabled() const override;
protected:
friend class NativeTheme;
@@ -260,6 +262,8 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme,
// Returns a handle to the theme data.
HANDLE GetThemeHandle(ThemeName theme_name) const;
+ void RegisterThemeRegkeyObserver();
+
typedef HRESULT (WINAPI* DrawThemeBackgroundPtr)(HANDLE theme,
HDC hdc,
int part_id,
@@ -314,6 +318,9 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme,
// Handle to uxtheme.dll.
HMODULE theme_dll_;
+ // Dark Mode registry key.
+ base::win::RegKey hkcu_themes_regkey_;
+
// A cache of open theme handles.
mutable HANDLE theme_handles_[LAST];
diff --git a/chromium/ui/native_theme/test_native_theme.cc b/chromium/ui/native_theme/test_native_theme.cc
new file mode 100644
index 00000000000..200eb212eff
--- /dev/null
+++ b/chromium/ui/native_theme/test_native_theme.cc
@@ -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.
+
+#include "ui/native_theme/test_native_theme.h"
+
+namespace ui {
+
+TestNativeTheme::TestNativeTheme() {}
+TestNativeTheme::~TestNativeTheme() {}
+
+SkColor TestNativeTheme::GetSystemColor(ColorId color_id) const {
+ return SK_ColorRED;
+}
+
+gfx::Size TestNativeTheme::GetPartSize(Part part,
+ State state,
+ const ExtraParams& extra) const {
+ return gfx::Size();
+}
+
+void TestNativeTheme::Paint(cc::PaintCanvas* canvas,
+ Part part,
+ State state,
+ const gfx::Rect& rect,
+ const ExtraParams& extra) const {}
+
+bool TestNativeTheme::SupportsNinePatch(Part part) const {
+ return false;
+}
+
+gfx::Size TestNativeTheme::GetNinePatchCanvasSize(Part part) const {
+ return gfx::Size();
+}
+
+gfx::Rect TestNativeTheme::GetNinePatchAperture(Part part) const {
+ return gfx::Rect();
+}
+
+bool TestNativeTheme::UsesHighContrastColors() const {
+ return false;
+}
+
+bool TestNativeTheme::SystemDarkModeEnabled() const {
+ return dark_mode_;
+}
+
+} // namespace ui
diff --git a/chromium/ui/native_theme/test_native_theme.h b/chromium/ui/native_theme/test_native_theme.h
new file mode 100644
index 00000000000..bdfc278eac2
--- /dev/null
+++ b/chromium/ui/native_theme/test_native_theme.h
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_NATIVE_THEME_TEST_NATIVE_THEME_H_
+#define UI_NATIVE_THEME_TEST_NATIVE_THEME_H_
+
+#include "base/macros.h"
+#include "ui/native_theme/native_theme.h"
+
+namespace ui {
+
+class TestNativeTheme : public NativeTheme {
+ public:
+ TestNativeTheme();
+ ~TestNativeTheme() override;
+
+ // NativeTheme:
+ SkColor GetSystemColor(ColorId color_id) const override;
+ gfx::Size GetPartSize(Part part,
+ State state,
+ const ExtraParams& extra) const override;
+ void Paint(cc::PaintCanvas* canvas,
+ Part part,
+ State state,
+ const gfx::Rect& rect,
+ const ExtraParams& extra) const override;
+ bool SupportsNinePatch(Part part) const override;
+ gfx::Size GetNinePatchCanvasSize(Part part) const override;
+ gfx::Rect GetNinePatchAperture(Part part) const override;
+ bool UsesHighContrastColors() const override;
+ bool SystemDarkModeEnabled() const override;
+
+ void SetDarkMode(bool dark_mode) { dark_mode_ = dark_mode; }
+
+ private:
+ bool dark_mode_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(TestNativeTheme);
+};
+
+} // namespace ui
+
+#endif // UI_NATIVE_THEME_TEST_NATIVE_THEME_H_
diff --git a/chromium/ui/ozone/BUILD.gn b/chromium/ui/ozone/BUILD.gn
index b35403f1264..ce321ea83e6 100644
--- a/chromium/ui/ozone/BUILD.gn
+++ b/chromium/ui/ozone/BUILD.gn
@@ -5,9 +5,8 @@
import("//build/config/jumbo.gni")
import("//build/config/ui.gni")
import("//gpu/vulkan/features.gni")
-import("//ui/ozone/ozone.gni")
-import("//ui/ozone/ozone_extra.gni")
import("//testing/test.gni")
+import("//ui/ozone/ozone.gni")
assert(use_ozone)
@@ -72,7 +71,6 @@ constructor_list_cc_file = "$target_gen_dir/constructor_list.cc"
jumbo_component("ozone_base") {
sources = [
"ozone_base_export.h",
- "public/clipboard_delegate.h",
"public/cursor_factory_ozone.cc",
"public/cursor_factory_ozone.h",
"public/gl_ozone.h",
@@ -91,7 +89,9 @@ jumbo_component("ozone_base") {
"public/overlay_surface_candidate.h",
"public/ozone_switches.cc",
"public/ozone_switches.h",
+ "public/platform_clipboard.h",
"public/platform_screen.h",
+ "public/platform_window_surface.h",
"public/surface_factory_ozone.cc",
"public/surface_factory_ozone.h",
"public/surface_ozone_canvas.h",
@@ -132,6 +132,9 @@ jumbo_component("ozone_base") {
"//ui/ozone/public/interfaces",
"//ui/ozone/platform/*",
]
+
+ # Out of tree platforms can depend on this.
+ visibility += ozone_external_platform_visibility
}
source_set("platform") {
@@ -186,6 +189,9 @@ source_set("platform") {
# This is used for platform tests.
visibility += [ "//ui/ozone/platform/*" ]
+
+ # This can be used for out of tree platforms tests.
+ visibility += ozone_external_platform_visibility
}
jumbo_component("ozone") {
diff --git a/chromium/ui/ozone/common/BUILD.gn b/chromium/ui/ozone/common/BUILD.gn
index 5ad1bd36eec..562057e9bdd 100644
--- a/chromium/ui/ozone/common/BUILD.gn
+++ b/chromium/ui/ozone/common/BUILD.gn
@@ -31,7 +31,7 @@ source_set("common") {
deps = [
"//ui/gfx/ipc/color",
"//ui/gl",
- "//ui/gl:gl_features",
+ "//ui/gl:buildflags",
]
data_deps = [
@@ -39,4 +39,7 @@ source_set("common") {
]
visibility = [ "//ui/ozone/platform/*" ]
+
+ # Out of tree platforms can depend on this.
+ visibility += ozone_external_platform_visibility
}
diff --git a/chromium/ui/ozone/common/egl_util.cc b/chromium/ui/ozone/common/egl_util.cc
index cc0f48af7ea..1e1679cbf42 100644
--- a/chromium/ui/ozone/common/egl_util.cc
+++ b/chromium/ui/ozone/common/egl_util.cc
@@ -7,9 +7,9 @@
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "build/build_config.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_features.h"
#include "ui/gl/gl_implementation.h"
namespace ui {
diff --git a/chromium/ui/ozone/common/linux/BUILD.gn b/chromium/ui/ozone/common/linux/BUILD.gn
index 2bf3481ffe8..c808a515e14 100644
--- a/chromium/ui/ozone/common/linux/BUILD.gn
+++ b/chromium/ui/ozone/common/linux/BUILD.gn
@@ -30,6 +30,7 @@ source_set("gbm") {
deps = [
":drm",
"//base:base",
+ "//build/config/linux/libdrm",
"//third_party/minigbm",
"//ui/gfx:buffer_types",
"//ui/gfx:memory_buffer",
diff --git a/chromium/ui/ozone/demo/BUILD.gn b/chromium/ui/ozone/demo/BUILD.gn
index 5b7e6059daf..dc215dad7c3 100644
--- a/chromium/ui/ozone/demo/BUILD.gn
+++ b/chromium/ui/ozone/demo/BUILD.gn
@@ -39,7 +39,7 @@ source_set("ozone_demo_lib") {
]
if (is_fuchsia) {
- deps += [ "//third_party/fuchsia-sdk/sdk:policy" ]
+ deps += [ "//third_party/fuchsia-sdk/sdk:ui_policy" ]
}
}
diff --git a/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc b/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc
index 9bbb1357611..36ca50095e2 100644
--- a/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc
+++ b/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc
@@ -9,6 +9,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
@@ -157,9 +158,11 @@ void SkiaGlRenderer::Draw(SkCanvas* canvas, float fraction) {
}
// Draw a message with a nice black paint
- paint.setSubpixelText(true);
paint.setColor(SK_ColorBLACK);
- paint.setTextSize(32);
+
+ SkFont font;
+ font.setSize(32);
+ font.setSubpixel(true);
canvas->save();
static const char message[] = "Hello Ozone";
@@ -175,8 +178,7 @@ void SkiaGlRenderer::Draw(SkCanvas* canvas, float fraction) {
const char* text = use_ddl_ ? message_ddl : message;
// Draw the text
- canvas->drawText(text, strlen(text), 0, 0, paint);
-
+ canvas->drawString(text, 0, 0, font, paint);
canvas->restore();
}
diff --git a/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc b/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
index b609232ce75..06a28abadae 100644
--- a/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
+++ b/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h"
@@ -114,9 +114,8 @@ bool SurfacelessSkiaGlRenderer::BufferWrapper::Initialize(
OzonePlatform::GetInstance()
->GetSurfaceFactoryOzone()
->CreateNativePixmap(widget, size, format, gfx::BufferUsage::SCANOUT);
- scoped_refptr<gl::GLImageNativePixmap> image(
- new gl::GLImageNativePixmap(size, GL_BGRA_EXT));
- if (!image->Initialize(pixmap.get(), format)) {
+ auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(size, format);
+ if (!image->Initialize(pixmap.get())) {
LOG(ERROR) << "Failed to create GLImage";
return false;
}
@@ -171,7 +170,7 @@ bool SurfacelessSkiaGlRenderer::Initialize() {
else
primary_plane_rect_ = gfx::Rect(size_);
- for (size_t i = 0; i < arraysize(buffers_); ++i) {
+ for (size_t i = 0; i < base::size(buffers_); ++i) {
buffers_[i].reset(new BufferWrapper());
if (!buffers_[i]->Initialize(gr_context_.get(), widget_,
primary_plane_rect_.size()))
@@ -180,7 +179,7 @@ bool SurfacelessSkiaGlRenderer::Initialize() {
if (command_line->HasSwitch(kEnableOverlay)) {
gfx::Size overlay_size = gfx::Size(size_.width() / 8, size_.height() / 8);
- for (size_t i = 0; i < arraysize(overlay_buffer_); ++i) {
+ for (size_t i = 0; i < base::size(overlay_buffer_); ++i) {
overlay_buffer_[i].reset(new BufferWrapper());
overlay_buffer_[i]->Initialize(gr_context_.get(),
gfx::kNullAcceleratedWidget, overlay_size);
@@ -269,7 +268,7 @@ void SurfacelessSkiaGlRenderer::PostRenderFrameTask(
std::unique_ptr<gfx::GpuFence> gpu_fence) {
switch (result) {
case gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS:
- for (size_t i = 0; i < arraysize(buffers_); ++i) {
+ for (size_t i = 0; i < base::size(buffers_); ++i) {
buffers_[i].reset(new BufferWrapper());
if (!buffers_[i]->Initialize(gr_context_.get(), widget_,
primary_plane_rect_.size()))
diff --git a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc b/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc
index 06c7f39d79b..fa0ce693c43 100644
--- a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc
+++ b/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc
@@ -85,9 +85,8 @@ bool SurfacelessGlRenderer::BufferWrapper::Initialize(
OzonePlatform::GetInstance()
->GetSurfaceFactoryOzone()
->CreateNativePixmap(widget, size, format, gfx::BufferUsage::SCANOUT);
- scoped_refptr<gl::GLImageNativePixmap> image(
- new gl::GLImageNativePixmap(size, GL_BGRA_EXT));
- if (!image->Initialize(pixmap.get(), format)) {
+ auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(size, format);
+ if (!image->Initialize(pixmap.get())) {
LOG(ERROR) << "Failed to create GLImage";
return false;
}
diff --git a/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc b/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
index d6479922ca8..5335857d692 100644
--- a/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
+++ b/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
@@ -55,9 +55,8 @@ class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase {
client_pixmap->Unmap();
}
- scoped_refptr<gl::GLImageNativePixmap> image(new gl::GLImageNativePixmap(
- size, gl::GLImageNativePixmap::GetInternalFormatForTesting(format)));
- EXPECT_TRUE(image->Initialize(pixmap.get(), pixmap->GetBufferFormat()));
+ auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(size, format);
+ EXPECT_TRUE(image->Initialize(pixmap.get()));
return image;
}
diff --git a/chromium/ui/ozone/ozone.gni b/chromium/ui/ozone/ozone.gni
index 07c1d347bc0..d1cd5a7ab8a 100644
--- a/chromium/ui/ozone/ozone.gni
+++ b/chromium/ui/ozone/ozone.gni
@@ -6,6 +6,10 @@ import("//build/config/chromecast_build.gni")
import("//build/config/ui.gni")
declare_args() {
+ # Ozone extra platforms file path. Can be overridden to build out of
+ # tree ozone platforms.
+ ozone_extra_path = "//ui/ozone/ozone_extra.gni"
+
# Select platforms automatically. Turn this off for manual control.
ozone_auto_platforms = use_ozone
}
@@ -79,6 +83,13 @@ declare_args() {
}
}
+import(ozone_extra_path)
+
+_ozone_extra_directory = get_path_info(ozone_extra_path, "dir")
+
+# Extra paths to add to targets visibility list.
+ozone_external_platform_visibility = [ "$_ozone_extra_directory/*" ]
+
assert(use_ozone || !(ozone_platform_cast || ozone_platform_gbm ||
ozone_platform_headless || ozone_platform_x11 ||
ozone_platform_wayland || ozone_platform_windows ||
diff --git a/chromium/ui/ozone/platform/drm/DEPS b/chromium/ui/ozone/platform/drm/DEPS
index 078fa013e3a..1a3b3300206 100644
--- a/chromium/ui/ozone/platform/drm/DEPS
+++ b/chromium/ui/ozone/platform/drm/DEPS
@@ -2,8 +2,8 @@ include_rules = [
"+mojo/public",
"+services/service_manager",
"+services/ws",
+ "+ui/base/buildflags.h", # Doesn't bring in all of ui/base.
"+ui/base/ui_base_features.h",
"+ui/base/ui_base_switches.h",
- "+ui/base/ui_features.h", # UI features doesn't bring in all of ui/base.
"+ui/display/util",
]
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.cc b/chromium/ui/ozone/platform/drm/common/drm_util.cc
index efb043d5fcc..7af691f73d4 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util.cc
@@ -666,7 +666,7 @@ gfx::ColorSpace GetColorSpaceFromEdid(const display::EdidParser& edid_parser) {
return gfx::ColorSpace();
}
- SkMatrix44 color_space_as_matrix;
+ skcms_Matrix3x3 color_space_as_matrix;
if (!primaries.toXYZD50(&color_space_as_matrix)) {
EmitEdidColorSpaceChecksOutcomeUma(
EdidColorSpaceChecksOutcome::kErrorCannotExtractToXYZD50);
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
index 5e4e8c9d8b1..43c4b3bb660 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
@@ -9,6 +9,7 @@
#include <map>
+#include "base/stl_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColorSpace.h"
@@ -321,10 +322,10 @@ TEST_F(DrmUtilTest, GetColorSpaceFromEdid) {
.fBY = 0.043945f,
.fWX = 0.313477f,
.fWY = 0.329102f};
- SkMatrix44 expected_hpz32x_toXYZ50_matrix;
+ skcms_Matrix3x3 expected_hpz32x_toXYZ50_matrix;
expected_hpz32x_primaries.toXYZD50(&expected_hpz32x_toXYZ50_matrix);
const std::vector<uint8_t> hpz32x_edid(kHPz32x,
- kHPz32x + arraysize(kHPz32x) - 1);
+ kHPz32x + base::size(kHPz32x) - 1);
const gfx::ColorSpace expected_hpz32x_color_space =
gfx::ColorSpace::CreateCustom(
expected_hpz32x_toXYZ50_matrix,
@@ -346,9 +347,10 @@ TEST_F(DrmUtilTest, GetColorSpaceFromEdid) {
.fBY = 0.090820f,
.fWX = 0.313477f,
.fWY = 0.329102f};
- SkMatrix44 expected_samus_toXYZ50_matrix;
+ skcms_Matrix3x3 expected_samus_toXYZ50_matrix;
expected_samus_primaries.toXYZD50(&expected_samus_toXYZ50_matrix);
- const std::vector<uint8_t> samus_edid(kSamus, kSamus + arraysize(kSamus) - 1);
+ const std::vector<uint8_t> samus_edid(kSamus,
+ kSamus + base::size(kSamus) - 1);
const gfx::ColorSpace expected_samus_color_space =
gfx::ColorSpace::CreateCustom(
expected_samus_toXYZ50_matrix,
@@ -370,9 +372,9 @@ TEST_F(DrmUtilTest, GetColorSpaceFromEdid) {
.fBY = 0.059570f,
.fWX = 0.312500f,
.fWY = 0.328125f};
- SkMatrix44 expected_eve_toXYZ50_matrix;
+ skcms_Matrix3x3 expected_eve_toXYZ50_matrix;
expected_eve_primaries.toXYZD50(&expected_eve_toXYZ50_matrix);
- const std::vector<uint8_t> eve_edid(kEve, kEve + arraysize(kEve) - 1);
+ const std::vector<uint8_t> eve_edid(kEve, kEve + base::size(kEve) - 1);
const gfx::ColorSpace expected_eve_color_space =
gfx::ColorSpace::CreateCustom(
expected_eve_toXYZ50_matrix,
@@ -387,7 +389,7 @@ TEST_F(DrmUtilTest, GetColorSpaceFromEdid) {
// Test with gamma marked as non-existent.
const std::vector<uint8_t> no_gamma_edid(
- kEdidWithNoGamma, kEdidWithNoGamma + arraysize(kEdidWithNoGamma) - 1);
+ kEdidWithNoGamma, kEdidWithNoGamma + base::size(kEdidWithNoGamma) - 1);
const gfx::ColorSpace no_gamma_color_space =
GetColorSpaceFromEdid(display::EdidParser(no_gamma_edid));
EXPECT_FALSE(no_gamma_color_space.IsValid());
@@ -412,7 +414,7 @@ TEST_F(DrmUtilTest, GetInvalidColorSpaceFromEdid) {
1);
const std::vector<uint8_t> invalid_edid(
- kInvalidEdid, kInvalidEdid + arraysize(kInvalidEdid) - 1);
+ kInvalidEdid, kInvalidEdid + base::size(kInvalidEdid) - 1);
const gfx::ColorSpace invalid_color_space =
GetColorSpaceFromEdid(display::EdidParser(invalid_edid));
EXPECT_FALSE(invalid_color_space.IsValid());
@@ -423,7 +425,7 @@ TEST_F(DrmUtilTest, GetInvalidColorSpaceFromEdid) {
2);
const std::vector<uint8_t> sst210_edid(kSST210,
- kSST210 + arraysize(kSST210) - 1);
+ kSST210 + base::size(kSST210) - 1);
const gfx::ColorSpace sst210_color_space =
GetColorSpaceFromEdid(display::EdidParser(sst210_edid));
EXPECT_FALSE(sst210_color_space.IsValid()) << sst210_color_space.ToString();
@@ -434,7 +436,7 @@ TEST_F(DrmUtilTest, GetInvalidColorSpaceFromEdid) {
1);
const std::vector<uint8_t> sst210_edid_2(
- kSST210Corrected, kSST210Corrected + arraysize(kSST210Corrected) - 1);
+ kSST210Corrected, kSST210Corrected + base::size(kSST210Corrected) - 1);
const gfx::ColorSpace sst210_color_space_2 =
GetColorSpaceFromEdid(display::EdidParser(sst210_edid_2));
EXPECT_FALSE(sst210_color_space_2.IsValid())
@@ -447,7 +449,7 @@ TEST_F(DrmUtilTest, GetInvalidColorSpaceFromEdid) {
const std::vector<uint8_t> broken_blue_edid(
kBrokenBluePrimaries,
- kBrokenBluePrimaries + arraysize(kBrokenBluePrimaries) - 1);
+ kBrokenBluePrimaries + base::size(kBrokenBluePrimaries) - 1);
const gfx::ColorSpace broken_blue_color_space =
GetColorSpaceFromEdid(display::EdidParser(broken_blue_edid));
EXPECT_FALSE(broken_blue_color_space.IsValid())
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
index 6563246e211..f800442687d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -6,7 +6,7 @@
#include <xf86drmMode.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
@@ -33,7 +33,7 @@ const ContentProtectionMapping kContentProtectionStates[] = {
uint32_t GetContentProtectionValue(drmModePropertyRes* property,
display::HDCPState state) {
std::string name;
- for (size_t i = 0; i < arraysize(kContentProtectionStates); ++i) {
+ for (size_t i = 0; i < base::size(kContentProtectionStates); ++i) {
if (kContentProtectionStates[i].state == state) {
name = kContentProtectionStates[i].name;
break;
@@ -141,7 +141,7 @@ bool DrmDisplay::GetHDCPState(display::HDCPState* state) {
std::string name =
GetEnumNameForProperty(connector.get(), hdcp_property.get());
- for (size_t i = 0; i < arraysize(kContentProtectionStates); ++i) {
+ for (size_t i = 0; i < base::size(kContentProtectionStates); ++i) {
if (name == kContentProtectionStates[i].name) {
*state = kContentProtectionStates[i].state;
VLOG(3) << "HDCP state: " << *state << " (" << name << ")";
@@ -178,6 +178,10 @@ void DrmDisplay::SetColorMatrix(const std::vector<float>& color_matrix) {
}
}
+void DrmDisplay::SetBackgroundColor(const uint64_t background_color) {
+ drm_->plane_manager()->SetBackgroundColor(crtc_, background_color);
+}
+
void DrmDisplay::SetGammaCorrection(
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut) {
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.h b/chromium/ui/ozone/platform/drm/gpu/drm_display.h
index 2ffc4d2e235..16f2dae4996 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.h
@@ -49,6 +49,7 @@ class DrmDisplay {
bool GetHDCPState(display::HDCPState* state);
bool SetHDCPState(display::HDCPState state);
void SetColorMatrix(const std::vector<float>& color_matrix);
+ void SetBackgroundColor(const uint64_t background_color);
void SetGammaCorrection(
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut);
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 64272d290ee..232ae769424 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
@@ -202,6 +202,18 @@ void DrmGpuDisplayManager::SetColorMatrix(
display->SetColorMatrix(color_matrix);
}
+void DrmGpuDisplayManager::SetBackgroundColor(
+ int64_t display_id,
+ const uint64_t background_color) {
+ DrmDisplay* display = FindDisplay(display_id);
+ if (!display) {
+ LOG(ERROR) << "There is no display with ID" << display_id;
+ return;
+ }
+
+ display->SetBackgroundColor(background_color);
+}
+
void DrmGpuDisplayManager::SetGammaCorrection(
int64_t display_id,
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
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 8e0a1a88fc3..4a7669faddf 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
@@ -48,6 +48,8 @@ class DrmGpuDisplayManager {
bool SetHDCPState(int64_t display_id, display::HDCPState state);
void SetColorMatrix(int64_t display_id,
const std::vector<float>& color_matrix);
+ void SetBackgroundColor(int64_t display_id,
+ const uint64_t background_color);
void SetGammaCorrection(
int64_t display_id,
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
index 297ff19a6df..339663cde8b 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/logging.h"
+#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "third_party/libdrm/src/include/drm/drm_fourcc.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -356,7 +357,7 @@ void HardwareDisplayController::AllocateCursorBuffers() {
gfx::Size max_cursor_size = GetMaximumCursorSize(GetDrmDevice()->get_fd());
SkImageInfo info = SkImageInfo::MakeN32Premul(max_cursor_size.width(),
max_cursor_size.height());
- for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) {
+ for (size_t i = 0; i < base::size(cursor_buffers_); ++i) {
cursor_buffers_[i] = std::make_unique<DrmDumbBuffer>(GetDrmDevice());
// Don't register a framebuffer for cursors since they are special (they
// aren't modesetting buffers and drivers may fail to register them due to
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
index 69a2c6bd3b4..bb8799b0626 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
@@ -250,6 +250,16 @@ bool HardwareDisplayPlaneManager::SetColorMatrix(
return CommitColorMatrix(crtc_state->properties);
}
+void HardwareDisplayPlaneManager::SetBackgroundColor(
+ uint32_t crtc_id,
+ const uint64_t background_color) {
+ const int crtc_index = LookupCrtcIndex(crtc_id);
+ DCHECK_GE(crtc_index, 0);
+ CrtcState* crtc_state = &crtc_state_[crtc_index];
+
+ crtc_state->properties.background_color.value = background_color;
+}
+
bool HardwareDisplayPlaneManager::SetGammaCorrection(
uint32_t crtc_id,
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
@@ -336,6 +346,8 @@ bool HardwareDisplayPlaneManager::InitializeCrtcState() {
&state.properties.degamma_lut_size);
GetDrmPropertyForName(drm_, props.get(), "OUT_FENCE_PTR",
&state.properties.out_fence_ptr);
+ GetDrmPropertyForName(drm_, props.get(), "BACKGROUND_COLOR",
+ &state.properties.background_color);
num_crtcs_with_out_fence_ptr += (state.properties.out_fence_ptr.id != 0);
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
index e4de8f55139..45cd06ce454 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -71,6 +71,9 @@ class HardwareDisplayPlaneManager {
// on the CRTC with ID |crtc_id|.
bool SetColorMatrix(uint32_t crtc_id, const std::vector<float>& color_matrix);
+ // Sets the background color on the CRTC object with ID |crtc_id|.
+ void SetBackgroundColor(uint32_t crtc_id, const uint64_t background_color);
+
// Sets the degamma/gamma luts on the CRTC object with ID |crtc_id|.
bool SetGammaCorrection(
uint32_t crtc_id,
@@ -141,6 +144,7 @@ class HardwareDisplayPlaneManager {
DrmDevice::Property degamma_lut;
DrmDevice::Property degamma_lut_size;
DrmDevice::Property out_fence_ptr;
+ DrmDevice::Property background_color;
};
struct CrtcState {
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 3d1083b89fd..c1868d0f913 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
@@ -83,23 +83,26 @@ bool HardwareDisplayPlaneManagerAtomic::Commit(
crtcs.push_back(atomic_plane->crtc());
}
-#if defined(COMMIT_PROPERTIES_ON_PAGE_FLIP)
drmModeAtomicReqPtr request = plane_list->atomic_property_set.get();
-
- // Apply all CRTC properties in the page-flip so we don't block the swap chain
- // for a vsync.
- // TODO(dnicoara): See if we can apply these properties async using
- // DRM_MODE_ATOMIC_ASYNC_UPDATE flag when committing.
for (auto* const crtc : crtcs) {
int idx = LookupCrtcIndex(crtc->crtc());
+
+#if defined(COMMIT_PROPERTIES_ON_PAGE_FLIP)
+ // Apply all CRTC properties in the page-flip so we don't block the
+ // swap chain for a vsync.
+ // TODO(dnicoara): See if we can apply these properties async using
+ // DRM_MODE_ATOMIC_ASYNC_UPDATE flag when committing.
AddPropertyIfValid(request, crtc->crtc(),
crtc_state_[idx].properties.degamma_lut);
AddPropertyIfValid(request, crtc->crtc(),
crtc_state_[idx].properties.gamma_lut);
AddPropertyIfValid(request, crtc->crtc(), crtc_state_[idx].properties.ctm);
- }
#endif
+ AddPropertyIfValid(request, crtc->crtc(),
+ crtc_state_[idx].properties.background_color);
+ }
+
if (test_only) {
for (HardwareDisplayPlane* plane : plane_list->plane_list) {
plane->set_in_use(false);
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
index ded5335acaa..6103f40bf46 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
@@ -40,6 +40,7 @@ constexpr uint32_t kDegammaLutPropId = 306;
constexpr uint32_t kDegammaLutSizePropId = 307;
constexpr uint32_t kOutFencePtrPropId = 308;
constexpr uint32_t kInFormatsBlobPropId = 400;
+constexpr uint32_t kBackgroundColorPropId = 401;
const gfx::Size kDefaultBufferSize(2, 2);
@@ -164,6 +165,7 @@ void HardwareDisplayPlaneManagerTest::InitializeDrmState(
property_names_.insert({kDegammaLutPropId, "DEGAMMA_LUT"});
property_names_.insert({kDegammaLutSizePropId, "DEGAMMA_LUT_SIZE"});
property_names_.insert({kOutFencePtrPropId, "OUT_FENCE_PTR"});
+ property_names_.insert({kBackgroundColorPropId, "BACKGROUND_COLOR"});
}
void HardwareDisplayPlaneManagerTest::PerformPageFlip(
@@ -686,6 +688,39 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_Success) {
}
}
+TEST_P(HardwareDisplayPlaneManagerTest, SetBackgroundColor_Success) {
+ InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1);
+ crtc_properties_[0].properties.push_back(
+ {/* .id = */ kBackgroundColorPropId, /* .value = */ 0});
+ fake_drm_->InitializeState(crtc_properties_, plane_properties_,
+ property_names_, use_atomic_);
+ fake_drm_->plane_manager()->SetBackgroundColor(crtc_properties_[0].id, 0);
+ if (use_atomic_) {
+ ui::HardwareDisplayPlaneList state;
+ PerformPageFlip(/*crtc_idx=*/0, &state);
+ EXPECT_EQ(1, fake_drm_->get_commit_count());
+ EXPECT_EQ(0u, GetCrtcPropertyValue(crtc_properties_[0].id,
+ "BACKGROUND_COLOR"));
+ } else {
+ EXPECT_EQ(0, fake_drm_->get_set_object_property_count());
+ }
+
+ crtc_properties_[0].properties.push_back(
+ {/* .id = */ kBackgroundColorPropId, /* .value = */ 1});
+ fake_drm_->InitializeState(crtc_properties_, plane_properties_,
+ property_names_, use_atomic_);
+ fake_drm_->plane_manager()->SetBackgroundColor(crtc_properties_[0].id, 1);
+ if (use_atomic_) {
+ ui::HardwareDisplayPlaneList state;
+ PerformPageFlip(/*crtc_idx=*/0, &state);
+ EXPECT_EQ(2, fake_drm_->get_commit_count());
+ EXPECT_EQ(1u, GetCrtcPropertyValue(crtc_properties_[0].id,
+ "BACKGROUND_COLOR"));
+ } else {
+ EXPECT_EQ(0, fake_drm_->get_set_object_property_count());
+ }
+}
+
TEST_P(HardwareDisplayPlaneManagerAtomicTest,
CommitReturnsNullOutFenceIfOutFencePtrNotSupported) {
scoped_refptr<ui::DrmFramebuffer> fake_buffer2 =
diff --git a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
index 276002409b7..e657ac8a601 100644
--- a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
@@ -31,27 +31,21 @@ bool VulkanImplementationGbm::InitializeVulkanInstance() {
"VK_KHR_external_fence_capabilities",
"VK_KHR_get_physical_device_properties2",
};
- if (!vulkan_instance_.Initialize(required_extensions, {})) {
- vulkan_instance_.Destroy();
+ if (!vulkan_instance_.Initialize(required_extensions, {}))
return false;
- }
vkGetPhysicalDeviceExternalFencePropertiesKHR_ =
reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR>(
vkGetInstanceProcAddr(
vulkan_instance_.vk_instance(),
"vkGetPhysicalDeviceExternalFencePropertiesKHR"));
- if (!vkGetPhysicalDeviceExternalFencePropertiesKHR_) {
- vulkan_instance_.Destroy();
+ if (!vkGetPhysicalDeviceExternalFencePropertiesKHR_)
return false;
- }
vkGetFenceFdKHR_ = reinterpret_cast<PFN_vkGetFenceFdKHR>(
vkGetInstanceProcAddr(vulkan_instance_.vk_instance(), "vkGetFenceFdKHR"));
- if (!vkGetFenceFdKHR_) {
- vulkan_instance_.Destroy();
+ if (!vkGetFenceFdKHR_)
return false;
- }
return true;
}
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 3f7ec9f7d1a..e0a565aa7ae 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc
@@ -11,7 +11,7 @@
#include "base/files/file_path.h"
#include "base/posix/eintr_wrapper.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h"
namespace ui {
@@ -38,8 +38,11 @@ DrmDeviceHandle::DrmDeviceHandle() {
}
DrmDeviceHandle::~DrmDeviceHandle() {
- if (file_.is_valid())
- base::AssertBlockingAllowedDeprecated();
+ if (file_.is_valid()) {
+ base::ScopedBlockingCall scoped_blocking_call(
+ base::BlockingType::MAY_BLOCK);
+ file_.reset();
+ }
}
bool DrmDeviceHandle::Initialize(const base::FilePath& dev_path,
@@ -48,7 +51,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::AssertBlockingAllowedDeprecated();
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
int num_auth_attempts = 0;
bool logged_warning = false;
diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
index a2e555d874e..e0e2c30eb06 100644
--- a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -18,8 +18,8 @@
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "services/service_manager/public/cpp/binder_registry.h"
+#include "ui/base/buildflags.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
-#include "ui/base/ui_features.h"
#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"
diff --git a/chromium/ui/ozone/platform/scenic/BUILD.gn b/chromium/ui/ozone/platform/scenic/BUILD.gn
index 565b80d8b5e..3d448a59159 100644
--- a/chromium/ui/ozone/platform/scenic/BUILD.gn
+++ b/chromium/ui/ozone/platform/scenic/BUILD.gn
@@ -20,6 +20,8 @@ source_set("scenic") {
"scenic_gpu_service.h",
"scenic_screen.cc",
"scenic_screen.h",
+ "scenic_surface.cc",
+ "scenic_surface.h",
"scenic_surface_factory.cc",
"scenic_surface_factory.h",
"scenic_window.cc",
@@ -30,20 +32,23 @@ source_set("scenic") {
"scenic_window_manager.h",
]
- defines = [ "OZONE_IMPLEMENTATION" ]
+ defines = [
+ "OZONE_IMPLEMENTATION",
+ "VK_USE_PLATFORM_FUCHSIA",
+ ]
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",
+ "//third_party/fuchsia-sdk/sdk:ui_gfx",
+ "//third_party/fuchsia-sdk/sdk:ui_scenic",
+ "//third_party/fuchsia-sdk/sdk:ui_viewsv1",
+ "//third_party/fuchsia-sdk/sdk:ui_viewsv1token",
"//ui/base",
"//ui/display/manager",
"//ui/events:dom_keycode_converter",
@@ -59,7 +64,6 @@ source_set("scenic") {
sources += [
"vulkan_implementation_scenic.cc",
"vulkan_implementation_scenic.h",
- "vulkan_magma.h",
]
defines += [ "VK_USE_PLATFORM_MAGMA_KHR" ]
}
diff --git a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
index 9a044347006..31f56de9d96 100644
--- a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
@@ -124,17 +124,22 @@ class OzonePlatformScenic
base::MessageLoopCurrent::Get()->AddDestructionObserver(this);
- surface_factory_ =
- std::make_unique<ScenicSurfaceFactory>(window_manager_.get());
-
scenic_gpu_host_ = std::make_unique<ScenicGpuHost>(window_manager_.get());
+ scenic_gpu_host_ptr_ = scenic_gpu_host_->CreateHostProcessSelfBinding();
+
+ surface_factory_ =
+ std::make_unique<ScenicSurfaceFactory>(scenic_gpu_host_ptr_.get());
}
void InitializeGPU(const InitParams& params) override {
- scenic_gpu_service_ = std::make_unique<ScenicGpuService>();
+ // TODO(spang, crbug.com/923445): Add message loop to GPU tests.
+ if (base::ThreadTaskRunnerHandle::IsSet()) {
+ scenic_gpu_service_ = std::make_unique<ScenicGpuService>(
+ mojo::MakeRequest(&scenic_gpu_host_ptr_));
+ }
DCHECK(!surface_factory_);
surface_factory_ =
- std::make_unique<ScenicSurfaceFactory>(scenic_gpu_service_.get());
+ std::make_unique<ScenicSurfaceFactory>(scenic_gpu_host_ptr_.get());
}
base::MessageLoop::Type GetMessageLoopTypeForGpu() override {
@@ -165,6 +170,8 @@ class OzonePlatformScenic
std::unique_ptr<ScenicGpuService> scenic_gpu_service_;
std::unique_ptr<ScenicSurfaceFactory> surface_factory_;
+ mojom::ScenicGpuHostPtr scenic_gpu_host_ptr_;
+
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
index afb7c6ee210..ad21783d613 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc
@@ -35,7 +35,8 @@ namespace ui {
ScenicGpuHost::ScenicGpuHost(ScenicWindowManager* scenic_window_manager)
: scenic_window_manager_(scenic_window_manager),
- binding_(this),
+ host_binding_(this),
+ gpu_binding_(this),
ui_thread_runner_(base::ThreadTaskRunnerHandle::Get()),
weak_ptr_factory_(this) {
DETACH_FROM_THREAD(io_thread_checker_);
@@ -45,6 +46,13 @@ ScenicGpuHost::~ScenicGpuHost() {
DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
}
+mojom::ScenicGpuHostPtr ScenicGpuHost::CreateHostProcessSelfBinding() {
+ DCHECK(!host_binding_.is_bound());
+ mojom::ScenicGpuHostPtr gpu_host;
+ host_binding_.Bind(mojo::MakeRequest(&gpu_host));
+ return gpu_host;
+}
+
void ScenicGpuHost::ExportParent(int32_t surface_handle,
mojo::ScopedHandle export_token_mojo) {
DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
@@ -87,8 +95,8 @@ void ScenicGpuHost::OnGpuServiceLaunchedOnUI(
DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
mojom::ScenicGpuHostPtr gpu_host;
- binding_.Close();
- binding_.Bind(mojo::MakeRequest(&gpu_host));
+ gpu_binding_.Close();
+ gpu_binding_.Bind(mojo::MakeRequest(&gpu_host));
gpu_service_.Bind(std::move(gpu_service_ptr_info));
gpu_service_->Initialize(std::move(gpu_host));
diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h
index 5c0cdeab043..26bc4024269 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h
@@ -32,6 +32,10 @@ class ScenicGpuHost : public mojom::ScenicGpuHost,
ScenicGpuHost(ScenicWindowManager* scenic_window_manager);
~ScenicGpuHost() override;
+ // Creates browser process binding. This is used to create a software output
+ // on the UI thread.
+ mojom::ScenicGpuHostPtr CreateHostProcessSelfBinding();
+
// mojom::ScenicGpuHost:
void ExportParent(int32_t surface_handle,
mojo::ScopedHandle export_token_mojo) override;
@@ -58,7 +62,8 @@ class ScenicGpuHost : public mojom::ScenicGpuHost,
mojom::ScenicGpuHostRequest scenic_gpu_host_request);
ScenicWindowManager* const scenic_window_manager_;
- mojo::Binding<mojom::ScenicGpuHost> binding_;
+ mojo::Binding<mojom::ScenicGpuHost> host_binding_;
+ mojo::Binding<mojom::ScenicGpuHost> gpu_binding_;
mojom::ScenicGpuServicePtr gpu_service_;
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_runner_;
diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc b/chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc
index 2d10d52533b..49a8c5ae806 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc
@@ -29,9 +29,8 @@ void FulfillInterfaceRequest(
} // namespace
-ScenicGpuService::ScenicGpuService()
- : gpu_host_request_(mojo::MakeRequest(&gpu_host_)),
- weak_ptr_factory_(this) {}
+ScenicGpuService::ScenicGpuService(mojom::ScenicGpuHostRequest gpu_host_request)
+ : gpu_host_request_(std::move(gpu_host_request)), weak_ptr_factory_(this) {}
ScenicGpuService::~ScenicGpuService() {}
diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_service.h b/chromium/ui/ozone/platform/scenic/scenic_gpu_service.h
index 8bb67458052..07774e0ca30 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_gpu_service.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_service.h
@@ -22,11 +22,9 @@ namespace ui {
// so that surfaces can present to Scenic views managed by the browser.
class ScenicGpuService : public mojom::ScenicGpuService {
public:
- ScenicGpuService();
+ ScenicGpuService(mojom::ScenicGpuHostRequest gpu_host_request);
~ScenicGpuService() override;
- mojom::ScenicGpuHost* gpu_host() { return gpu_host_.get(); }
-
base::RepeatingCallback<void(mojom::ScenicGpuServiceRequest)>
GetBinderCallback();
@@ -36,7 +34,6 @@ class ScenicGpuService : public mojom::ScenicGpuService {
private:
void AddBinding(mojom::ScenicGpuServiceRequest request);
- mojom::ScenicGpuHostPtr gpu_host_;
mojom::ScenicGpuHostRequest gpu_host_request_;
mojo::BindingSet<mojom::ScenicGpuService> binding_set_;
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface.cc b/chromium/ui/ozone/platform/scenic/scenic_surface.cc
new file mode 100644
index 00000000000..ae540c1aa33
--- /dev/null
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface.cc
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/scenic/scenic_surface.h"
+
+#include <lib/ui/scenic/cpp/commands.h>
+#include <lib/zx/eventpair.h>
+
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "ui/ozone/platform/scenic/scenic_gpu_host.h"
+#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
+
+namespace ui {
+
+ScenicSurface::ScenicSurface(
+ ScenicSurfaceFactory* scenic_surface_factory,
+ gfx::AcceleratedWidget window,
+ scenic::SessionPtrAndListenerRequest sesion_and_listener_request)
+ : scenic_session_(std::move(sesion_and_listener_request)),
+ parent_(&scenic_session_),
+ shape_(&scenic_session_),
+ material_(&scenic_session_),
+ scenic_surface_factory_(scenic_surface_factory),
+ window_(window) {
+ shape_.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
+ shape_.SetMaterial(material_);
+ scenic_surface_factory->AddSurface(window, this);
+}
+
+ScenicSurface::~ScenicSurface() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ scenic_surface_factory_->RemoveSurface(window_);
+}
+
+void ScenicSurface::SetTextureToNewImagePipe(
+ fidl::InterfaceRequest<fuchsia::images::ImagePipe> image_pipe_request) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ uint32_t image_pipe_id = scenic_session_.AllocResourceId();
+ scenic_session_.Enqueue(scenic::NewCreateImagePipeCmd(
+ image_pipe_id, std::move(image_pipe_request)));
+ material_.SetTexture(image_pipe_id);
+ scenic_session_.ReleaseResource(image_pipe_id);
+ scenic_session_.Present(
+ /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
+}
+
+void ScenicSurface::SetTextureToImage(const scenic::Image& image) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ material_.SetTexture(image);
+}
+
+mojo::ScopedHandle ScenicSurface::CreateParentExportToken() {
+ // Scenic does not care about order here; it's totally fine for imports to
+ // cause exports, and that's what's done here.
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ zx::eventpair export_token;
+ parent_.BindAsRequest(&export_token);
+ parent_.AddChild(shape_);
+ scenic_session_.Present(
+ /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
+ return mojo::WrapPlatformHandle(
+ mojo::PlatformHandle(std::move(export_token)));
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface.h b/chromium/ui/ozone/platform/scenic/scenic_surface.h
new file mode 100644
index 00000000000..080739b257c
--- /dev/null
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface.h
@@ -0,0 +1,72 @@
+// 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_SURFACE_H_
+#define UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_H_
+
+#include <fuchsia/ui/scenic/cpp/fidl.h>
+#include <lib/ui/scenic/cpp/resources.h>
+#include <lib/ui/scenic/cpp/session.h>
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/public/platform_window_surface.h"
+
+namespace ui {
+
+class ScenicSurfaceFactory;
+
+// Holder for Scenic resources backing rendering surface.
+//
+// This object creates some simple Scenic resources for containing a window's
+// texture, and attaches them to the parent View (by sending an IPC to the
+// browser process).
+//
+// The texture is updated through an image pipe.
+class ScenicSurface : public ui::PlatformWindowSurface {
+ public:
+ ScenicSurface(
+ ScenicSurfaceFactory* scenic_surface_factory,
+ gfx::AcceleratedWidget window,
+ scenic::SessionPtrAndListenerRequest sesion_and_listener_request);
+ ~ScenicSurface() override;
+
+ // Sets the texture of the surface to a new image pipe.
+ void SetTextureToNewImagePipe(
+ fidl::InterfaceRequest<fuchsia::images::ImagePipe> image_pipe_request);
+
+ // Sets the texture of the surface to an image resource.
+ void SetTextureToImage(const scenic::Image& image);
+
+ // Creates token to links the surface to the window in the browser process.
+ mojo::ScopedHandle CreateParentExportToken();
+
+ void AssertBelongsToCurrentThread() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ }
+
+ scenic::Session* scenic_session() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return &scenic_session_;
+ }
+
+ private:
+ scenic::Session scenic_session_;
+ scenic::ImportNode parent_;
+ scenic::ShapeNode shape_;
+ scenic::Material material_;
+
+ ScenicSurfaceFactory* const scenic_surface_factory_;
+ const gfx::AcceleratedWidget window_;
+
+ THREAD_CHECKER(thread_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(ScenicSurface);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_H_
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
index d104ae08484..acd32738dc4 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -17,6 +17,7 @@
#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_surface.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"
@@ -105,25 +106,17 @@ class ScenicPixmap : public gfx::NativePixmap {
} // namespace
-ScenicSurfaceFactory::ScenicSurfaceFactory(ScenicWindowManager* 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;
+ScenicSurfaceFactory::ScenicSurfaceFactory(mojom::ScenicGpuHost* gpu_host)
+ : gpu_host_(gpu_host),
+ egl_implementation_(std::make_unique<GLOzoneEGLScenic>()),
+ weak_ptr_factory_(this) {
+ // TODO(spang, crbug.com/923445): Add message loop to GPU tests.
+ if (base::ThreadTaskRunnerHandle::IsSet())
+ main_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+}
-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();
+ScenicSurfaceFactory::~ScenicSurfaceFactory() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
std::vector<gl::GLImplementation>
@@ -141,14 +134,22 @@ GLOzone* ScenicSurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
}
}
+std::unique_ptr<PlatformWindowSurface>
+ScenicSurfaceFactory::CreatePlatformWindowSurface(
+ gfx::AcceleratedWidget widget) {
+ auto surface =
+ std::make_unique<ScenicSurface>(this, widget, CreateScenicSession());
+ main_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&ScenicSurfaceFactory::LinkSurfaceToParent,
+ weak_ptr_factory_.GetWeakPtr(), widget,
+ surface->CreateParentExportToken()));
+ return surface;
+}
+
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>(GetScenic(), window);
+ ScenicSurface* surface = GetSurface(widget);
+ return std::make_unique<ScenicWindowCanvas>(surface);
}
scoped_refptr<gfx::NativePixmap> ScenicSurfaceFactory::CreateNativePixmap(
@@ -162,12 +163,72 @@ scoped_refptr<gfx::NativePixmap> ScenicSurfaceFactory::CreateNativePixmap(
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
ScenicSurfaceFactory::CreateVulkanImplementation() {
- if (!scenic_gpu_service_)
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!gpu_host_)
LOG(FATAL) << "Vulkan implementation requires InitializeForGPU";
- return std::make_unique<ui::VulkanImplementationScenic>(
- scenic_gpu_service_->gpu_host(), GetScenic());
+ return std::make_unique<ui::VulkanImplementationScenic>(this);
}
#endif
+void ScenicSurfaceFactory::AddSurface(gfx::AcceleratedWidget widget,
+ ScenicSurface* surface) {
+ base::AutoLock lock(surface_lock_);
+ DCHECK(!base::ContainsKey(surface_map_, widget));
+ surface->AssertBelongsToCurrentThread();
+ surface_map_.insert(std::make_pair(widget, surface));
+}
+
+void ScenicSurfaceFactory::RemoveSurface(gfx::AcceleratedWidget widget) {
+ base::AutoLock lock(surface_lock_);
+ auto it = surface_map_.find(widget);
+ DCHECK(it != surface_map_.end());
+ ScenicSurface* surface = it->second;
+ surface->AssertBelongsToCurrentThread();
+ surface_map_.erase(it);
+}
+
+ScenicSurface* ScenicSurfaceFactory::GetSurface(gfx::AcceleratedWidget widget) {
+ base::AutoLock lock(surface_lock_);
+ auto it = surface_map_.find(widget);
+ DCHECK(it != surface_map_.end());
+ ScenicSurface* surface = it->second;
+ surface->AssertBelongsToCurrentThread();
+ return surface;
+}
+
+scenic::SessionPtrAndListenerRequest
+ScenicSurfaceFactory::CreateScenicSession() {
+ fuchsia::ui::scenic::SessionPtr session;
+ fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener_handle;
+ auto listener_request = listener_handle.NewRequest();
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ScenicSurfaceFactory::CreateScenicSessionOnMainThread,
+ weak_ptr_factory_.GetWeakPtr(), session.NewRequest(),
+ listener_handle.Bind()));
+ return {std::move(session), std::move(listener_request)};
+}
+
+void ScenicSurfaceFactory::CreateScenicSessionOnMainThread(
+ fidl::InterfaceRequest<fuchsia::ui::scenic::Session> session_request,
+ fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ 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";
+ });
+ }
+ scenic_->CreateSession(std::move(session_request), std::move(listener));
+}
+
+void ScenicSurfaceFactory::LinkSurfaceToParent(
+ gfx::AcceleratedWidget widget,
+ mojo::ScopedHandle export_token_mojo) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ gpu_host_->ExportParent(widget, std::move(export_token_mojo));
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
index 9a34b1003f4..8ee99a3f0d7 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
@@ -6,28 +6,35 @@
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_FACTORY_H_
#include <fuchsia/ui/scenic/cpp/fidl.h>
+#include <lib/ui/scenic/cpp/session.h>
#include <memory>
#include <vector>
+#include "base/containers/flat_map.h"
#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_annotations.h"
+#include "base/threading/thread_checker.h"
#include "gpu/vulkan/buildflags.h"
+#include "mojo/public/cpp/system/handle.h"
#include "ui/ozone/public/gl_ozone.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_host.mojom.h"
#include "ui/ozone/public/surface_factory_ozone.h"
namespace ui {
-class ScenicWindowManager;
-class ScenicGpuService;
+class ScenicSurface;
class ScenicSurfaceFactory : public SurfaceFactoryOzone {
public:
- explicit ScenicSurfaceFactory(ScenicWindowManager* window_manager);
- explicit ScenicSurfaceFactory(ScenicGpuService* scenic_gpu_service);
+ explicit ScenicSurfaceFactory(mojom::ScenicGpuHost* gpu_host);
~ScenicSurfaceFactory() override;
// SurfaceFactoryOzone implementation.
std::vector<gl::GLImplementation> GetAllowedGLImplementations() override;
GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
+ std::unique_ptr<PlatformWindowSurface> CreatePlatformWindowSurface(
+ gfx::AcceleratedWidget widget) override;
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
@@ -40,14 +47,53 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone {
override;
#endif
+ // Registers a surface for a |widget|.
+ //
+ // Must be called on the thread that owns the surface.
+ void AddSurface(gfx::AcceleratedWidget widget, ScenicSurface* surface)
+ LOCKS_EXCLUDED(surface_lock_);
+
+ // Removes a surface for a |widget|.
+ //
+ // Must be called on the thread that owns the surface.
+ void RemoveSurface(gfx::AcceleratedWidget widget)
+ LOCKS_EXCLUDED(surface_lock_);
+
+ // Returns the surface for a |widget|.
+ //
+ // Must be called on the thread that owns the surface.
+ ScenicSurface* GetSurface(gfx::AcceleratedWidget widget)
+ LOCKS_EXCLUDED(surface_lock_);
+
private:
- fuchsia::ui::scenic::Scenic* GetScenic();
+ // Creates a new scenic session on any thread.
+ scenic::SessionPtrAndListenerRequest CreateScenicSession();
+
+ // Creates a new scenic session on the main thread.
+ void CreateScenicSessionOnMainThread(
+ fidl::InterfaceRequest<fuchsia::ui::scenic::Session> session_request,
+ fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener);
+
+ // Links a surface to its parent in the host process.
+ void LinkSurfaceToParent(gfx::AcceleratedWidget widget,
+ mojo::ScopedHandle export_token_mojo);
- ScenicWindowManager* const window_manager_ = nullptr;
- ScenicGpuService* scenic_gpu_service_ = nullptr;
+ base::flat_map<gfx::AcceleratedWidget, ScenicSurface*> surface_map_
+ GUARDED_BY(surface_lock_);
+ base::Lock surface_lock_;
+
+ mojom::ScenicGpuHost* const gpu_host_;
std::unique_ptr<GLOzone> egl_implementation_;
+
fuchsia::ui::scenic::ScenicPtr scenic_;
+ // Task runner for thread that |scenic_| and |gpu_host_| are bound on.
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+
+ THREAD_CHECKER(thread_checker_);
+
+ base::WeakPtrFactory<ScenicSurfaceFactory> weak_ptr_factory_;
+
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 804ef7b5ae5..5403f8ea18a 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.cc
@@ -34,8 +34,7 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
parent_node_(&scenic_session_),
node_(&scenic_session_),
input_node_(&scenic_session_),
- render_node_(&scenic_session_),
- input_listener_binding_(this) {
+ render_node_(&scenic_session_) {
scenic_session_.set_error_handler(
fit::bind_member(this, &ScenicWindow::OnScenicError));
scenic_session_.set_event_handler(
@@ -68,15 +67,6 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
view_listener_binding_.set_error_handler(
fit::bind_member(this, &ScenicWindow::OnViewError));
- // 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(
- fuchsia::ui::input::InputConnection::Name_,
- input_connection_.NewRequest().TakeChannel());
- input_connection_->SetEventListener(input_listener_binding_.NewBinding());
-
// Call Present() to ensure that the scenic session commands are processed,
// which is necessary to receive metrics event from Scenic.
scenic_session_.Present(
@@ -234,8 +224,8 @@ void ScenicWindow::OnScenicError(zx_status_t status) {
}
void ScenicWindow::OnScenicEvents(
- fidl::VectorPtr<fuchsia::ui::scenic::Event> events) {
- for (const auto& event : *events) {
+ std::vector<fuchsia::ui::scenic::Event> events) {
+ for (const auto& event : events) {
if (event.is_gfx()) {
if (!event.gfx().is_metrics())
continue;
@@ -266,20 +256,6 @@ void ScenicWindow::OnScenicEvents(
}
}
-void ScenicWindow::OnEvent(fuchsia::ui::input::InputEvent event,
- OnEventCallback callback) {
- bool result = false;
-
- if (event.is_focus()) {
- delegate_->OnActivationChanged(event.focus().focused);
- result = true;
- } else {
- result = event_dispatcher_.ProcessEvent(event);
- }
-
- callback(result);
-}
-
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 9bb57b78e0b..3ea813fc21f 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.h
@@ -5,7 +5,6 @@
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_
-#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>
@@ -29,7 +28,6 @@ class PlatformWindowDelegate;
class OZONE_EXPORT ScenicWindow : public PlatformWindow,
public fuchsia::ui::viewsv1::ViewListener,
- public fuchsia::ui::input::InputListener,
public InputEventDispatcherDelegate {
public:
// Both |window_manager| and |delegate| must outlive the ScenicWindow.
@@ -71,14 +69,9 @@ class OZONE_EXPORT ScenicWindow : public PlatformWindow,
void OnPropertiesChanged(fuchsia::ui::viewsv1::ViewProperties properties,
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;
-
// Callbacks for |scenic_session_|.
void OnScenicError(zx_status_t status);
- void OnScenicEvents(fidl::VectorPtr<fuchsia::ui::scenic::Event> events);
+ void OnScenicEvents(std::vector<fuchsia::ui::scenic::Event> events);
// InputEventDispatcher::Delegate interface.
void DispatchEvent(ui::Event* event) override;
@@ -125,11 +118,6 @@ class OZONE_EXPORT ScenicWindow : public PlatformWindow,
// Current view size in device pixels.
gfx::Size size_pixels_;
- // InputConnection and InputListener binding used to receive input events from
- // the view.
- fuchsia::ui::input::InputConnectionPtr input_connection_;
- fidl::Binding<fuchsia::ui::input::InputListener> input_listener_binding_;
-
DISALLOW_COPY_AND_ASSIGN(ScenicWindow);
};
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc
index 439e73ea33d..15591483898 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc
@@ -66,21 +66,8 @@ void ScenicWindowCanvas::Frame::CopyDirtyRegionFrom(const Frame& frame) {
dirty_region.setEmpty();
}
-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(ScenicSurface* scenic_surface)
+ : scenic_surface_(scenic_surface) {}
ScenicWindowCanvas::~ScenicWindowCanvas() = default;
@@ -90,7 +77,7 @@ void ScenicWindowCanvas::ResizeCanvas(const gfx::Size& viewport_size) {
// Allocate new buffers with the new size.
for (int i = 0; i < kNumBuffers; ++i) {
- frames_[i].Initialize(viewport_size_, &scenic_session_);
+ frames_[i].Initialize(viewport_size_, scenic_surface_->scenic_session());
}
}
@@ -151,7 +138,8 @@ void ScenicWindowCanvas::PresentCanvas(const gfx::Rect& damage) {
viewport_size_.width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
scenic::Image image(*frames_[current_frame_].scenic_memory, 0,
std::move(info));
- material_.SetTexture(image);
+ // TODO(spang): Consider using ImagePipe for consistency with vulkan path.
+ scenic_surface_->SetTextureToImage(image);
// Create release fence for the current buffer or reset it if it already
// exists.
@@ -172,9 +160,10 @@ 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_session_.EnqueueReleaseFence(std::move(release_fence_dup));
- scenic_session_.Present(/*presentation_time=*/0,
- [](fuchsia::images::PresentationInfo info) {});
+ scenic_surface_->scenic_session()->EnqueueReleaseFence(
+ std::move(release_fence_dup));
+ scenic_surface_->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 8d366fbc06e..f385a9650ce 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h
@@ -12,6 +12,7 @@
#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_surface.h"
#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
@@ -27,10 +28,9 @@ class ScenicWindow;
// ScenicWindow.
class ScenicWindowCanvas : public SurfaceOzoneCanvas {
public:
- // |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);
+ // |scenic_surface| must outlive the canvas. ScenicSurface owns the
+ // scenic::Session used in this class for all drawing operations.
+ explicit ScenicWindowCanvas(ScenicSurface* scenic_surface);
~ScenicWindowCanvas() override;
// SurfaceOzoneCanvas implementation.
@@ -73,8 +73,6 @@ class ScenicWindowCanvas : public SurfaceOzoneCanvas {
SkRegion dirty_region;
};
- ScenicWindow* const window_;
-
Frame frames_[kNumBuffers];
// Buffer index in |frames_| for the frame that's currently being rendered.
@@ -83,9 +81,7 @@ class ScenicWindowCanvas : public SurfaceOzoneCanvas {
// View size in device pixels.
gfx::Size viewport_size_;
- scenic::Session scenic_session_;
- scenic::ImportNode parent_;
- scenic::Material material_;
+ ScenicSurface* const scenic_surface_;
DISALLOW_COPY_AND_ASSIGN(ScenicWindowCanvas);
};
diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
index 27a79babbbe..d2a4379dfeb 100644
--- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
@@ -7,6 +7,7 @@
#include <lib/ui/scenic/cpp/commands.h>
#include <lib/ui/scenic/cpp/session.h>
#include <lib/zx/channel.h>
+#include <vulkan/vulkan.h>
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
@@ -18,77 +19,16 @@
#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_surface.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"
-#include "ui/ozone/platform/scenic/vulkan_magma.h"
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(
- mojom::ScenicGpuHost* scenic_gpu_host,
- fuchsia::ui::scenic::Scenic* scenic)
- : scenic_gpu_host_(scenic_gpu_host), scenic_(scenic) {}
+ ScenicSurfaceFactory* scenic_surface_factory)
+ : scenic_surface_factory_(scenic_surface_factory) {}
VulkanImplementationScenic::~VulkanImplementationScenic() = default;
@@ -105,30 +45,21 @@ bool VulkanImplementationScenic::InitializeVulkanInstance() {
gpu::GetVulkanFunctionPointers();
vulkan_function_pointers->vulkan_loader_library_ = handle;
std::vector<const char*> required_extensions = {
- VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_MAGMA_SURFACE_EXTENSION_NAME,
+ VK_KHR_SURFACE_EXTENSION_NAME,
+ VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME,
};
std::vector<const char*> required_layers = {
- "VK_LAYER_GOOGLE_image_pipe_swapchain",
+ "VK_LAYER_FUCHSIA_imagepipe_swapchain",
};
- if (!vulkan_instance_.Initialize(required_extensions, required_layers)) {
- vulkan_instance_.Destroy();
+ if (!vulkan_instance_.Initialize(required_extensions, required_layers))
return false;
- }
-
- vkCreateMagmaSurfaceKHR_ = vkGetInstanceProcAddr(
- vulkan_instance_.vk_instance(), "vkCreateMagmaSurfaceKHR");
- if (!vkCreateMagmaSurfaceKHR_) {
- vulkan_instance_.Destroy();
- return false;
- }
- vkGetPhysicalDeviceMagmaPresentationSupportKHR_ =
- vkGetInstanceProcAddr(vulkan_instance_.vk_instance(),
- "vkGetPhysicalDeviceMagmaPresentationSupportKHR");
- if (!vkGetPhysicalDeviceMagmaPresentationSupportKHR_) {
- vulkan_instance_.Destroy();
+ vkCreateImagePipeSurfaceFUCHSIA_ =
+ reinterpret_cast<PFN_vkCreateImagePipeSurfaceFUCHSIA>(
+ vkGetInstanceProcAddr(vulkan_instance_.vk_instance(),
+ "vkCreateImagePipeSurfaceFUCHSIA"));
+ if (!vkCreateImagePipeSurfaceFUCHSIA_)
return false;
- }
return true;
}
@@ -139,41 +70,27 @@ VkInstance VulkanImplementationScenic::GetVulkanInstance() {
std::unique_ptr<gpu::VulkanSurface>
VulkanImplementationScenic::CreateViewSurface(gfx::AcceleratedWidget window) {
- 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;
+ ScenicSurface* scenic_surface = scenic_surface_factory_->GetSurface(window);
scenic_surface->SetTextureToNewImagePipe(image_pipe.NewRequest());
VkSurfaceKHR surface;
- VkMagmaSurfaceCreateInfoKHR surface_create_info = {};
- surface_create_info.sType = VK_STRUCTURE_TYPE_MAGMA_SURFACE_CREATE_INFO_KHR;
+ VkImagePipeSurfaceCreateInfoFUCHSIA surface_create_info = {};
+ surface_create_info.sType =
+ VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA;
+ surface_create_info.flags = 0;
surface_create_info.imagePipeHandle =
image_pipe.Unbind().TakeChannel().release();
- VkResult result =
- reinterpret_cast<PFN_vkCreateMagmaSurfaceKHR>(vkCreateMagmaSurfaceKHR_)(
- GetVulkanInstance(), &surface_create_info, nullptr, &surface);
+ VkResult result = vkCreateImagePipeSurfaceFUCHSIA_(
+ GetVulkanInstance(), &surface_create_info, nullptr, &surface);
if (result != VK_SUCCESS) {
// This shouldn't fail, and we don't know whether imagePipeHandle was closed
// if it does.
- LOG(FATAL) << "vkCreateMagmaSurfaceKHR failed: " << result;
+ LOG(FATAL) << "vkCreateImagePipeSurfaceFUCHSIA failed: " << result;
}
- // 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));
+ return std::make_unique<gpu::VulkanSurface>(GetVulkanInstance(), surface);
}
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 3f859adfee2..e61afca7060 100644
--- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
+++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
@@ -14,10 +14,11 @@
namespace ui {
+class ScenicSurfaceFactory;
+
class VulkanImplementationScenic : public gpu::VulkanImplementation {
public:
- VulkanImplementationScenic(mojom::ScenicGpuHost* scenic_gpu_host,
- fuchsia::ui::scenic::Scenic* scenic);
+ VulkanImplementationScenic(ScenicSurfaceFactory* scenic_surface_factory);
~VulkanImplementationScenic() override;
// VulkanImplementation:
@@ -36,12 +37,11 @@ class VulkanImplementationScenic : public gpu::VulkanImplementation {
VkFence vk_fence) override;
private:
- mojom::ScenicGpuHost* const scenic_gpu_host_;
- fuchsia::ui::scenic::Scenic* const scenic_;
+ ScenicSurfaceFactory* const scenic_surface_factory_;
gpu::VulkanInstance vulkan_instance_;
- PFN_vkVoidFunction vkCreateMagmaSurfaceKHR_ = nullptr;
- PFN_vkVoidFunction vkGetPhysicalDeviceMagmaPresentationSupportKHR_ = nullptr;
+ PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA_ =
+ nullptr;
DISALLOW_COPY_AND_ASSIGN(VulkanImplementationScenic);
};
diff --git a/chromium/ui/ozone/platform/scenic/vulkan_magma.h b/chromium/ui/ozone/platform/scenic/vulkan_magma.h
deleted file mode 100644
index df222e83efc..00000000000
--- a/chromium/ui/ozone/platform/scenic/vulkan_magma.h
+++ /dev/null
@@ -1,159 +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_VULKAN_MAGMA_H_
-#define UI_OZONE_PLATFORM_SCENIC_VULKAN_MAGMA_H_
-
-// These definitions are from
-// https://fuchsia.googlesource.com/third_party/vulkan_loader_and_validation_layers/+/master/include/vulkan/vulkan.h
-// TODO(spang): Remove these once the definitions go upstream.
-
-#include <vulkan/vulkan.h>
-
-#if !defined(VK_KHR_external_memory_fuchsia)
-#define VK_KHR_external_memory_fuchsia 1
-#define VK_KHR_EXTERNAL_MEMORY_FUCHSIA_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_MEMORY_FUCHSIA_EXTENSION_NAME \
- "VK_KHR_external_memory_fuchsia"
-
-typedef struct VkImportMemoryFuchsiaHandleInfoKHR {
- VkStructureType sType;
- const void* pNext;
- VkExternalMemoryHandleTypeFlagBitsKHR handleType;
- uint32_t handle;
-} VkImportMemoryFuchsiaHandleInfoKHR;
-
-typedef struct VkMemoryFuchsiaHandlePropertiesKHR {
- VkStructureType sType;
- void* pNext;
- uint32_t memoryTypeBits;
-} VkMemoryFuchsiaHandlePropertiesKHR;
-
-typedef struct VkMemoryGetFuchsiaHandleInfoKHR {
- VkStructureType sType;
- const void* pNext;
- VkDeviceMemory memory;
- VkExternalMemoryHandleTypeFlagBitsKHR handleType;
-} VkMemoryGetFuchsiaHandleInfoKHR;
-
-typedef VkResult(VKAPI_PTR* PFN_vkGetMemoryFuchsiaHandleKHR)(
- VkDevice device,
- const VkMemoryGetFuchsiaHandleInfoKHR* pGetFuchsiaHandleInfo,
- uint32_t* pFuchsiaHandle);
-typedef VkResult(VKAPI_PTR* PFN_vkGetMemoryFuchsiaHandlePropertiesKHR)(
- VkDevice device,
- VkExternalMemoryHandleTypeFlagBitsKHR handleType,
- uint32_t fuchsiaHandle,
- VkMemoryFuchsiaHandlePropertiesKHR* pMemoryFuchsiaHandleProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFuchsiaHandleKHR(
- VkDevice device,
- const VkMemoryGetFuchsiaHandleInfoKHR* pGetFuchsiaHandleInfo,
- uint32_t* pFuchsiaHandle);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFuchsiaHandlePropertiesKHR(
- VkDevice device,
- VkExternalMemoryHandleTypeFlagBitsKHR handleType,
- uint32_t fuchsiaHandle,
- VkMemoryFuchsiaHandlePropertiesKHR* pMemoryFuchsiaHandleProperties);
-#endif
-
-#endif // !defined(VK_KHR_external_memory_fuchsia)
-
-#if !defined(VK_KHR_external_semaphore_fuchsia)
-#define VK_KHR_external_semaphore_fuchsia 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_FUCHSIA_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_FUCHSIA_EXTENSION_NAME \
- "VK_KHR_external_semaphore_fuchsia"
-
-typedef struct VkImportSemaphoreFuchsiaHandleInfoKHR {
- VkStructureType sType;
- const void* pNext;
- VkSemaphore semaphore;
- VkSemaphoreImportFlagsKHR flags;
- VkExternalSemaphoreHandleTypeFlagBitsKHR handleType;
- uint32_t handle;
-} VkImportSemaphoreFuchsiaHandleInfoKHR;
-
-typedef struct VkSemaphoreGetFuchsiaHandleInfoKHR {
- VkStructureType sType;
- const void* pNext;
- VkSemaphore semaphore;
- VkExternalSemaphoreHandleTypeFlagBitsKHR handleType;
-} VkSemaphoreGetFuchsiaHandleInfoKHR;
-
-typedef VkResult(VKAPI_PTR* PFN_vkImportSemaphoreFuchsiaHandleKHR)(
- VkDevice device,
- const VkImportSemaphoreFuchsiaHandleInfoKHR*
- pImportSemaphoreFuchsiaHandleInfo);
-typedef VkResult(VKAPI_PTR* PFN_vkGetSemaphoreFuchsiaHandleKHR)(
- VkDevice device,
- const VkSemaphoreGetFuchsiaHandleInfoKHR* pGetFuchsiaHandleInfo,
- uint32_t* pFuchsiaHandle);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL
-vkImportSemaphoreFuchsiaHandleKHR(VkDevice device,
- const VkImportSemaphoreFuchsiaHandleInfoKHR*
- pImportSemaphoreFuchsiaHandleInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFuchsiaHandleKHR(
- VkDevice device,
- const VkSemaphoreGetFuchsiaHandleInfoKHR* pGetFuchsiaHandleInfo,
- uint32_t* pFuchsiaHandle);
-#endif
-
-#endif // !defined(VK_KHR_external_semaphore_fuchsia)
-
-#if defined(VK_USE_PLATFORM_MAGMA_KHR) && !defined(VK_KHR_magma_surface)
-#define VK_KHR_magma_surface 1
-#define VK_KHR_MAGMA_SURFACE_SPEC_VERSION 1
-#define VK_KHR_MAGMA_SURFACE_EXTENSION_NAME "VK_KHR_magma_surface"
-
-typedef VkFlags VkMagmaSurfaceCreateFlagsKHR;
-
-typedef struct VkMagmaSurfaceCreateInfoKHR {
- VkStructureType sType;
- const void* pNext;
- uint32_t imagePipeHandle;
- uint32_t width;
- uint32_t height;
-} VkMagmaSurfaceCreateInfoKHR;
-
-typedef VkResult(VKAPI_PTR* PFN_vkCreateMagmaSurfaceKHR)(
- VkInstance instance,
- const VkMagmaSurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface);
-typedef VkBool32(VKAPI_PTR* PFN_vkGetPhysicalDeviceMagmaPresentationSupportKHR)(
- VkPhysicalDevice physicalDevice,
- uint32_t queueFamilyIndex);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL
-vkCreateMagmaSurfaceKHR(VkInstance instance,
- const VkMagmaSurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface);
-
-VKAPI_ATTR VkBool32 VKAPI_CALL
-vkGetPhysicalDeviceMagmaPresentationSupportKHR(VkPhysicalDevice physicalDevice,
- uint32_t queueFamilyIndex);
-#endif
-#endif // defined(VK_USE_PLATFORM_MAGMA_KHR) && !defined(VK_KHR_magma_surface)
-
-#if !defined(VK_GOOGLE_image_usage_scanout)
-
-#define VK_GOOGLE_image_usage_scanout 1
-#define VK_GOOGLE_IMAGE_USAGE_SCANOUT_SPEC_VERSION 1
-#define VK_GOOGLE_IMAGE_USAGE_SCANOUT_EXTENSION_NAME \
- "VK_GOOGLE_image_usage_scanout"
-
-#define VK_STRUCTURE_TYPE_MAGMA_SURFACE_CREATE_INFO_KHR \
- (static_cast<VkStructureType>(1001002000))
-
-#endif // !defined(VK_GOOGLE_image_usage_scanout)
-
-#endif // UI_OZONE_PLATFORM_MAGMA_VULKAN_MAGMA_H_
diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn
index d3d30fc8787..efd5e2d552d 100644
--- a/chromium/ui/ozone/platform/wayland/BUILD.gn
+++ b/chromium/ui/ozone/platform/wayland/BUILD.gn
@@ -98,7 +98,7 @@ source_set("wayland") {
"//third_party/wayland-protocols:text_input_protocol",
"//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/base",
- "//ui/base:ui_features",
+ "//ui/base:buildflags",
"//ui/base/ime/linux",
"//ui/display/manager",
"//ui/events",
@@ -171,9 +171,10 @@ source_set("wayland_unittests") {
"//testing/gmock",
"//testing/gtest",
"//third_party/wayland:wayland_server",
+ "//third_party/wayland-protocols:text_input_protocol",
"//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/base",
- "//ui/base:ui_features",
+ "//ui/base:buildflags",
"//ui/base/ime/linux",
"//ui/events/ozone:events_ozone_layout",
"//ui/ozone:platform",
diff --git a/chromium/ui/ozone/platform/wayland/DEPS b/chromium/ui/ozone/platform/wayland/DEPS
index 56a383a0459..1bdd1df6c10 100644
--- a/chromium/ui/ozone/platform/wayland/DEPS
+++ b/chromium/ui/ozone/platform/wayland/DEPS
@@ -1,6 +1,6 @@
include_rules = [
+ "+ui/base/buildflags.h", # Doesn't bring in all of ui/base.
"+ui/base/hit_test.h", # UI hit test doesn't bring in all of ui/base.
- "+ui/base/ui_features.h", # UI features doesn't bring in all of ui/base.
"+ui/base/ui_base_features.h",
"+ui/base/ime/composition_text.h",
"+ui/base/ime/linux/linux_input_method_context.h",
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 62d42fcc06f..8c662b9b5c6 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -37,7 +37,7 @@ GbmPixmapWayland::~GbmPixmapWayland() {
bool GbmPixmapWayland::InitializeBuffer(gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage) {
- TRACE_EVENT1("Wayland", "GbmPixmapWayland::InitializeBuffer", "size",
+ TRACE_EVENT1("wayland", "GbmPixmapWayland::InitializeBuffer", "size",
size.ToString());
uint32_t flags = 0;
switch (usage) {
diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 0bba90d5b5d..9c7267bdddb 100644
--- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -5,8 +5,8 @@
#include "ui/ozone/platform/wayland/ozone_platform_wayland.h"
#include "base/memory/ptr_util.h"
+#include "ui/base/buildflags.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
-#include "ui/base/ui_features.h"
#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"
@@ -115,7 +115,13 @@ class OzonePlatformWayland : public OzonePlatform {
// The WaylandConnection and the WaylandOutputManager must be created before
// PlatformScreen.
DCHECK(connection_ && connection_->wayland_output_manager());
- return connection_->wayland_output_manager()->CreateWaylandScreen();
+ return connection_->wayland_output_manager()->CreateWaylandScreen(
+ connection_.get());
+ }
+
+ PlatformClipboard* GetPlatformClipboard() override {
+ DCHECK(connection_);
+ return connection_->GetPlatformClipboard();
}
bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
diff --git a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc
index 393336d1371..91b1a1e8eb0 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc
@@ -77,7 +77,7 @@ bool WaylandBufferManager::CreateBuffer(base::File file,
const std::vector<uint64_t>& modifiers,
uint32_t planes_count,
uint32_t buffer_id) {
- TRACE_EVENT2("Wayland", "WaylandBufferManager::CreateZwpLinuxDmabuf",
+ TRACE_EVENT2("wayland", "WaylandBufferManager::CreateZwpLinuxDmabuf",
"Format", format, "Buffer id", buffer_id);
static const struct zwp_linux_buffer_params_v1_listener params_listener = {
@@ -121,7 +121,7 @@ bool WaylandBufferManager::ScheduleBufferSwap(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::Rect& damage_region,
wl::BufferSwapCallback callback) {
- TRACE_EVENT1("Wayland", "WaylandBufferManager::ScheduleSwapBuffer",
+ TRACE_EVENT1("wayland", "WaylandBufferManager::ScheduleSwapBuffer",
"Buffer id", buffer_id);
if (!ValidateDataFromGpu(widget, buffer_id))
@@ -152,7 +152,7 @@ bool WaylandBufferManager::ScheduleBufferSwap(gfx::AcceleratedWidget widget,
}
bool WaylandBufferManager::DestroyBuffer(uint32_t buffer_id) {
- TRACE_EVENT1("Wayland", "WaylandBufferManager::DestroyZwpLinuxDmabuf",
+ TRACE_EVENT1("wayland", "WaylandBufferManager::DestroyZwpLinuxDmabuf",
"Buffer id", buffer_id);
auto it = buffers_.find(buffer_id);
@@ -181,7 +181,7 @@ void WaylandBufferManager::ClearState() {
// TODO(msisov): handle buffer swap failure or success.
bool WaylandBufferManager::SwapBuffer(Buffer* buffer) {
- TRACE_EVENT1("Wayland", "WaylandBufferManager::SwapBuffer", "Buffer id",
+ TRACE_EVENT1("wayland", "WaylandBufferManager::SwapBuffer", "Buffer id",
buffer->buffer_id);
WaylandWindow* window = connection_->GetWindow(buffer->widget);
diff --git a/chromium/ui/ozone/platform/wayland/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/wayland_connection.cc
index 72c8d8b527d..b6a7c798fbc 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_connection.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_connection.cc
@@ -35,6 +35,8 @@ constexpr uint32_t kMaxDeviceManagerVersion = 3;
constexpr uint32_t kMaxWpPresentationVersion = 1;
constexpr uint32_t kMaxTextInputManagerVersion = 1;
+constexpr uint32_t kMinWlOutputVersion = 2;
+
std::unique_ptr<WaylandDataSource> CreateWaylandDataSource(
WaylandDataDeviceManager* data_device_manager,
WaylandConnection* connection) {
@@ -203,25 +205,25 @@ void WaylandConnection::ScheduleBufferSwap(
}
}
-ClipboardDelegate* WaylandConnection::GetClipboardDelegate() {
+PlatformClipboard* WaylandConnection::GetPlatformClipboard() {
return this;
}
void WaylandConnection::OfferClipboardData(
- const ClipboardDelegate::DataMap& data_map,
- ClipboardDelegate::OfferDataClosure callback) {
+ const PlatformClipboard::DataMap& data_map,
+ PlatformClipboard::OfferDataClosure callback) {
if (!data_source_) {
data_source_ = CreateWaylandDataSource(data_device_manager_.get(), this);
data_source_->WriteToClipboard(data_map);
}
- data_source_->UpdataDataMap(data_map);
+ data_source_->UpdateDataMap(data_map);
std::move(callback).Run();
}
void WaylandConnection::RequestClipboardData(
const std::string& mime_type,
- ClipboardDelegate::DataMap* data_map,
- ClipboardDelegate::RequestDataClosure callback) {
+ PlatformClipboard::DataMap* data_map,
+ PlatformClipboard::RequestDataClosure callback) {
read_clipboard_closure_ = std::move(callback);
DCHECK(data_map);
@@ -289,7 +291,7 @@ void WaylandConnection::ResetPointerFlags() {
}
void WaylandConnection::GetAvailableMimeTypes(
- ClipboardDelegate::GetMimeTypesClosure callback) {
+ PlatformClipboard::GetMimeTypesClosure callback) {
std::move(callback).Run(data_device_->GetAvailableMimeTypes());
}
@@ -418,7 +420,15 @@ void WaylandConnection::Global(void* data,
xdg_shell_use_unstable_version(connection->shell_.get(),
XDG_SHELL_VERSION_CURRENT);
} else if (base::EqualsCaseInsensitiveASCII(interface, "wl_output")) {
- wl::Object<wl_output> output = wl::Bind<wl_output>(registry, name, 1);
+ if (version < kMinWlOutputVersion) {
+ LOG(ERROR)
+ << "Unable to bind to the unsupported wl_output object with version= "
+ << version << ". Minimum supported version is "
+ << kMinWlOutputVersion;
+ return;
+ }
+
+ wl::Object<wl_output> output = wl::Bind<wl_output>(registry, name, version);
if (!output) {
LOG(ERROR) << "Failed to bind to wl_output global";
return;
diff --git a/chromium/ui/ozone/platform/wayland/wayland_connection.h b/chromium/ui/ozone/platform/wayland/wayland_connection.h
index d2487cd967b..6c4c081b22b 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_connection.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_connection.h
@@ -21,8 +21,8 @@
#include "ui/ozone/platform/wayland/wayland_output.h"
#include "ui/ozone/platform/wayland/wayland_pointer.h"
#include "ui/ozone/platform/wayland/wayland_touch.h"
-#include "ui/ozone/public/clipboard_delegate.h"
#include "ui/ozone/public/interfaces/wayland/wayland_connection.mojom.h"
+#include "ui/ozone/public/platform_clipboard.h"
namespace ui {
@@ -30,8 +30,9 @@ class WaylandBufferManager;
class WaylandOutputManager;
class WaylandWindow;
+// TODO: factor out PlatformClipboard to a separate class.
class WaylandConnection : public PlatformEventSource,
- public ClipboardDelegate,
+ public PlatformClipboard,
public ozone::mojom::WaylandConnection,
public base::MessagePumpLibevent::FdWatcher {
public:
@@ -105,21 +106,21 @@ class WaylandConnection : public PlatformEventSource,
}
// Clipboard implementation.
- ClipboardDelegate* GetClipboardDelegate();
+ PlatformClipboard* GetPlatformClipboard();
void DataSourceCancelled();
void SetClipboardData(const std::string& contents,
const std::string& mime_type);
- // ClipboardDelegate.
+ // PlatformClipboard.
void OfferClipboardData(
- const ClipboardDelegate::DataMap& data_map,
- ClipboardDelegate::OfferDataClosure callback) override;
+ const PlatformClipboard::DataMap& data_map,
+ PlatformClipboard::OfferDataClosure callback) override;
void RequestClipboardData(
const std::string& mime_type,
- ClipboardDelegate::DataMap* data_map,
- ClipboardDelegate::RequestDataClosure callback) override;
+ PlatformClipboard::DataMap* data_map,
+ PlatformClipboard::RequestDataClosure callback) override;
void GetAvailableMimeTypes(
- ClipboardDelegate::GetMimeTypesClosure callback) override;
+ PlatformClipboard::GetMimeTypesClosure callback) override;
bool IsSelectionOwner() override;
// Returns bound pointer to own mojo interface.
@@ -222,7 +223,7 @@ class WaylandConnection : public PlatformEventSource,
// Holds a temporary instance of the client's clipboard content
// so that we can asynchronously write to it.
- ClipboardDelegate::DataMap* data_map_ = nullptr;
+ PlatformClipboard::DataMap* data_map_ = nullptr;
// Stores the callback to be invoked upon data reading from clipboard.
RequestDataClosure read_clipboard_closure_;
diff --git a/chromium/ui/ozone/platform/wayland/wayland_data_device_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
index f8fe5abf620..b0b03858197 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
@@ -10,23 +10,23 @@
#include "ui/events/base_event_utils.h"
#include "ui/ozone/platform/wayland/fake_server.h"
#include "ui/ozone/platform/wayland/wayland_test.h"
-#include "ui/ozone/public/clipboard_delegate.h"
+#include "ui/ozone/public/platform_clipboard.h"
namespace ui {
// This class mocks how a real clipboard/ozone client would
-// hook to ClipboardDelegate, with one difference: real clients
+// hook to PlatformClipboard, with one difference: real clients
// have no access to the WaylandConnection instance like this
// MockClipboardClient impl does. Instead, clients and ozone gets
// plumbbed up by calling the appropriated Ozone API,
-// OzonePlatform::GetClipboardDelegate.
+// OzonePlatform::GetPlatformClipboard.
class MockClipboardClient {
public:
MockClipboardClient(WaylandConnection* connection) {
DCHECK(connection);
// See comment above for reasoning to access the WaylandConnection
// directly from here.
- delegate_ = connection->GetClipboardDelegate();
+ delegate_ = connection->GetPlatformClipboard();
DCHECK(delegate_);
}
@@ -35,7 +35,7 @@ class MockClipboardClient {
// Fill the clipboard backing store with sample data.
void SetData(const std::string& utf8_text,
const std::string& mime_type,
- ClipboardDelegate::OfferDataClosure callback) {
+ PlatformClipboard::OfferDataClosure callback) {
// This mimics how Mus' ClipboardImpl writes data to the DataMap.
std::vector<char> object_map(utf8_text.begin(), utf8_text.end());
char* object_data = &object_map.front();
@@ -46,7 +46,7 @@ class MockClipboardClient {
}
void ReadData(const std::string& mime_type,
- ClipboardDelegate::RequestDataClosure callback) {
+ PlatformClipboard::RequestDataClosure callback) {
delegate_->RequestClipboardData(mime_type, &data_types_,
std::move(callback));
}
@@ -54,8 +54,8 @@ class MockClipboardClient {
bool IsSelectionOwner() { return delegate_->IsSelectionOwner(); }
private:
- ClipboardDelegate* delegate_ = nullptr;
- ClipboardDelegate::DataMap data_types_;
+ PlatformClipboard* delegate_ = nullptr;
+ PlatformClipboard::DataMap data_types_;
DISALLOW_COPY_AND_ASSIGN(MockClipboardClient);
};
diff --git a/chromium/ui/ozone/platform/wayland/wayland_data_source.cc b/chromium/ui/ozone/platform/wayland/wayland_data_source.cc
index e1fe23b6c19..1acf9b9ca14 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_data_source.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_data_source.cc
@@ -27,7 +27,7 @@ WaylandDataSource::WaylandDataSource(wl_data_source* data_source,
WaylandDataSource::~WaylandDataSource() = default;
void WaylandDataSource::WriteToClipboard(
- const ClipboardDelegate::DataMap& data_map) {
+ const PlatformClipboard::DataMap& data_map) {
for (const auto& data : data_map) {
wl_data_source_offer(data_source_.get(), data.first.c_str());
if (strcmp(data.first.c_str(), kTextMimeType) == 0)
@@ -39,8 +39,8 @@ void WaylandDataSource::WriteToClipboard(
wl_display_flush(connection_->display());
}
-void WaylandDataSource::UpdataDataMap(
- const ClipboardDelegate::DataMap& data_map) {
+void WaylandDataSource::UpdateDataMap(
+ const PlatformClipboard::DataMap& data_map) {
data_map_ = data_map;
}
diff --git a/chromium/ui/ozone/platform/wayland/wayland_data_source.h b/chromium/ui/ozone/platform/wayland/wayland_data_source.h
index 33dfeb2f912..1ed57322abb 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_data_source.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_data_source.h
@@ -15,7 +15,7 @@
#include "base/macros.h"
#include "base/optional.h"
#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/public/clipboard_delegate.h"
+#include "ui/ozone/public/platform_clipboard.h"
namespace ui {
@@ -42,8 +42,8 @@ class WaylandDataSource {
connection_ = connection;
}
- void WriteToClipboard(const ClipboardDelegate::DataMap& data_map);
- void UpdataDataMap(const ClipboardDelegate::DataMap& data_map);
+ void WriteToClipboard(const PlatformClipboard::DataMap& data_map);
+ void UpdateDataMap(const PlatformClipboard::DataMap& data_map);
void Offer(const ui::OSExchangeData& data);
void SetAction(int operation);
void SetDragData(const DragDataMap& data_map);
@@ -71,7 +71,7 @@ class WaylandDataSource {
WaylandConnection* connection_ = nullptr;
WaylandWindow* source_window_ = nullptr;
- ClipboardDelegate::DataMap data_map_;
+ PlatformClipboard::DataMap data_map_;
DragDataMap drag_data_map_;
// Action selected by the compositor
uint32_t dnd_action_;
diff --git a/chromium/ui/ozone/platform/wayland/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/wayland_keyboard.cc
index b6568596683..a6d0ea7df04 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_keyboard.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_keyboard.cc
@@ -7,7 +7,7 @@
#include <sys/mman.h>
#include "base/files/scoped_file.h"
-#include "ui/base/ui_features.h"
+#include "ui/base/buildflags.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
diff --git a/chromium/ui/ozone/platform/wayland/wayland_object.h b/chromium/ui/ozone/platform/wayland/wayland_object.h
index 34984d3296a..6e5e1b08245 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_object.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_object.h
@@ -251,7 +251,7 @@ class Object : public std::unique_ptr<T, Deleter> {
Object() {}
explicit Object(T* obj) : std::unique_ptr<T, Deleter>(obj) {}
- uint32_t id() {
+ uint32_t id() const {
return wl_proxy_get_id(
reinterpret_cast<wl_proxy*>(std::unique_ptr<T, Deleter>::get()));
}
diff --git a/chromium/ui/ozone/platform/wayland/wayland_output.cc b/chromium/ui/ozone/platform/wayland/wayland_output.cc
index fd14f45d633..91cdf2c43bf 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_output.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_output.cc
@@ -63,16 +63,15 @@ void WaylandOutput::OutputHandleMode(void* data,
int32_t height,
int32_t refresh) {
WaylandOutput* wayland_output = static_cast<WaylandOutput*>(data);
- if (wayland_output && (flags & WL_OUTPUT_MODE_CURRENT)) {
- wayland_output->rect_in_physical_pixels_.set_width(width);
- wayland_output->rect_in_physical_pixels_.set_height(height);
- wayland_output->TriggerDelegateNotification();
- }
+ if (wayland_output && (flags & WL_OUTPUT_MODE_CURRENT))
+ wayland_output->rect_in_physical_pixels_.set_size(gfx::Size(width, height));
}
// static
void WaylandOutput::OutputHandleDone(void* data, struct wl_output* wl_output) {
- NOTIMPLEMENTED_LOG_ONCE();
+ WaylandOutput* wayland_output = static_cast<WaylandOutput*>(data);
+ if (wayland_output)
+ wayland_output->TriggerDelegateNotification();
}
// static
@@ -80,10 +79,8 @@ void WaylandOutput::OutputHandleScale(void* data,
struct wl_output* wl_output,
int32_t factor) {
WaylandOutput* wayland_output = static_cast<WaylandOutput*>(data);
- if (wayland_output) {
+ if (wayland_output)
wayland_output->device_scale_factor_ = factor;
- wayland_output->TriggerDelegateNotification();
- }
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/wayland_output_manager.cc b/chromium/ui/ozone/platform/wayland/wayland_output_manager.cc
index c9db25c35b4..82fe00a49d4 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_output_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_output_manager.cc
@@ -38,9 +38,9 @@ void WaylandOutputManager::AddWaylandOutput(const uint32_t output_id,
OnWaylandOutputAdded(output_id);
- // If WaylandScreen has already been created, the output can be initialized,
- // which results in setting up a wl_listener and getting the geometry and the
- // scaling factor from the Wayland Compositor.
+ // Even if WaylandScreen has not been created, the output still must be
+ // initialized, which results in setting up a wl_listener and getting the
+ // geometry and the scaling factor from the Wayland Compositor.
wayland_output_ptr->Initialize(this);
}
@@ -65,8 +65,9 @@ void WaylandOutputManager::RemoveWaylandOutput(const uint32_t output_id) {
OnWaylandOutputRemoved(output_id);
}
-std::unique_ptr<WaylandScreen> WaylandOutputManager::CreateWaylandScreen() {
- auto wayland_screen = std::make_unique<WaylandScreen>();
+std::unique_ptr<WaylandScreen> WaylandOutputManager::CreateWaylandScreen(
+ WaylandConnection* connection) {
+ auto wayland_screen = std::make_unique<WaylandScreen>(connection);
wayland_screen_ = wayland_screen->GetWeakPtr();
// As long as |wl_output| sends geometry and other events asynchronously (that
diff --git a/chromium/ui/ozone/platform/wayland/wayland_output_manager.h b/chromium/ui/ozone/platform/wayland/wayland_output_manager.h
index 5fcdced8a04..ef429190c99 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_output_manager.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_output_manager.h
@@ -19,6 +19,7 @@ struct wl_output;
namespace ui {
+class WaylandConnection;
class WaylandOutput;
class WaylandOutputManager : public WaylandOutput::Delegate {
@@ -33,7 +34,8 @@ class WaylandOutputManager : public WaylandOutput::Delegate {
void RemoveWaylandOutput(const uint32_t output_id);
// Creates a platform screen and feeds it with existing outputs.
- std::unique_ptr<WaylandScreen> CreateWaylandScreen();
+ std::unique_ptr<WaylandScreen> CreateWaylandScreen(
+ WaylandConnection* connection);
private:
void OnWaylandOutputAdded(uint32_t output_id);
diff --git a/chromium/ui/ozone/platform/wayland/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/wayland_pointer.cc
index f977f636681..4e7940cd8e9 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_pointer.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_pointer.cc
@@ -80,6 +80,7 @@ void WaylandPointer::Leave(void* data,
if (surface) {
WaylandWindow* window = WaylandWindow::FromSurface(surface);
window->set_pointer_focus(false);
+ window->set_has_implicit_grab(false);
pointer->window_with_pointer_focus_ = nullptr;
}
}
diff --git a/chromium/ui/ozone/platform/wayland/wayland_screen.cc b/chromium/ui/ozone/platform/wayland/wayland_screen.cc
index 98ef35e3f61..6906ee44929 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_screen.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_screen.cc
@@ -9,10 +9,15 @@
#include "ui/display/display_observer.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/wayland_window.h"
namespace ui {
-WaylandScreen::WaylandScreen() : weak_factory_(this) {}
+WaylandScreen::WaylandScreen(WaylandConnection* connection)
+ : connection_(connection), weak_factory_(this) {
+ DCHECK(connection_);
+}
WaylandScreen::~WaylandScreen() = default;
@@ -75,11 +80,11 @@ gfx::Point WaylandScreen::GetCursorScreenPoint() const {
gfx::AcceleratedWidget WaylandScreen::GetAcceleratedWidgetAtScreenPoint(
const gfx::Point& point) const {
- // TODO(msisov): implement this once wl_surface_listener::enter and ::leave
- // are used.
- //
- // https://crbug.com/890271
- NOTIMPLEMENTED_LOG_ONCE();
+ // It is safe to check only for focused windows and test if they contain the
+ // point or not.
+ auto* window = connection_->GetCurrentFocusedWindow();
+ if (window && window->GetBounds().Contains(point))
+ return window->GetWidget();
return gfx::kNullAcceleratedWidget;
}
diff --git a/chromium/ui/ozone/platform/wayland/wayland_screen.h b/chromium/ui/ozone/platform/wayland/wayland_screen.h
index f2de8d4dbb9..fe6f74f26cd 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_screen.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_screen.h
@@ -17,10 +17,12 @@
namespace ui {
+class WaylandConnection;
+
// A PlatformScreen implementation for Wayland.
class WaylandScreen : public PlatformScreen {
public:
- WaylandScreen();
+ explicit WaylandScreen(WaylandConnection* connection);
~WaylandScreen() override;
void OnOutputAdded(uint32_t output_id, bool is_primary);
@@ -48,6 +50,8 @@ class WaylandScreen : public PlatformScreen {
void RemoveObserver(display::DisplayObserver* observer) override;
private:
+ WaylandConnection* connection_ = nullptr;
+
display::DisplayList display_list_;
base::ObserverList<display::DisplayObserver> observers_;
diff --git a/chromium/ui/ozone/platform/wayland/wayland_screen_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_screen_unittest.cc
index 7eb9350f298..a84af11d06a 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_screen_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_screen_unittest.cc
@@ -11,6 +11,7 @@
#include "ui/ozone/platform/wayland/wayland_output_manager.h"
#include "ui/ozone/platform/wayland/wayland_screen.h"
#include "ui/ozone/platform/wayland/wayland_test.h"
+#include "ui/platform_window/platform_window_init_properties.h"
namespace ui {
@@ -69,12 +70,31 @@ class WaylandScreenTest : public WaylandTest {
output_manager_ = connection_->wayland_output_manager();
ASSERT_TRUE(output_manager_);
+
+ EXPECT_TRUE(output_manager_->IsPrimaryOutputReady());
+ platform_screen_ = output_manager_->CreateWaylandScreen(connection_.get());
}
protected:
+ std::unique_ptr<WaylandWindow> CreateWaylandWindowWithProperties(
+ const gfx::Rect& bounds,
+ PlatformWindowType window_type,
+ gfx::AcceleratedWidget parent_widget,
+ MockPlatformWindowDelegate* delegate) {
+ auto window = std::make_unique<WaylandWindow>(delegate, connection_.get());
+ PlatformWindowInitProperties properties;
+ properties.bounds = bounds;
+ properties.type = window_type;
+ properties.parent_widget = parent_widget;
+ EXPECT_TRUE(window->Initialize(std::move(properties)));
+ return window;
+ }
+
wl::MockOutput* output_ = nullptr;
WaylandOutputManager* output_manager_ = nullptr;
+ std::unique_ptr<WaylandScreen> platform_screen_;
+
private:
DISALLOW_COPY_AND_ASSIGN(WaylandScreenTest);
};
@@ -82,27 +102,21 @@ class WaylandScreenTest : public WaylandTest {
// Tests whether a primary output has been initialized before PlatformScreen is
// created.
TEST_P(WaylandScreenTest, OutputBaseTest) {
- EXPECT_TRUE(output_manager_->IsPrimaryOutputReady());
-
- std::unique_ptr<WaylandScreen> platform_screen =
- output_manager_->CreateWaylandScreen();
+ // IsPrimaryOutputReady and PlatformScreen creation is done in the
+ // initialization part of the tests.
// Ensure there is only one display, which is the primary one.
- auto& all_displays = platform_screen->GetAllDisplays();
+ auto& all_displays = platform_screen_->GetAllDisplays();
EXPECT_EQ(all_displays.size(), kNumberOfDisplays);
// Ensure the size property of the primary display.
- EXPECT_EQ(platform_screen->GetPrimaryDisplay().bounds(),
+ EXPECT_EQ(platform_screen_->GetPrimaryDisplay().bounds(),
gfx::Rect(0, 0, kOutputWidth, kOutputHeight));
}
TEST_P(WaylandScreenTest, MultipleOutputsAddedAndRemoved) {
- EXPECT_TRUE(output_manager_->IsPrimaryOutputReady());
- std::unique_ptr<WaylandScreen> platform_screen =
- output_manager_->CreateWaylandScreen();
-
TestDisplayObserver observer;
- platform_screen->AddObserver(&observer);
+ platform_screen_->AddObserver(&observer);
// Add a second display.
server_.CreateAndInitializeOutput();
@@ -111,7 +125,7 @@ TEST_P(WaylandScreenTest, MultipleOutputsAddedAndRemoved) {
// Ensure that second display is not a primary one and have a different id.
int64_t added_display_id = observer.GetDisplay().id();
- EXPECT_NE(platform_screen->GetPrimaryDisplay().id(), added_display_id);
+ EXPECT_NE(platform_screen_->GetPrimaryDisplay().id(), added_display_id);
// Remove the second output.
output_manager_->RemoveWaylandOutput(added_display_id);
@@ -129,25 +143,25 @@ TEST_P(WaylandScreenTest, MultipleOutputsAddedAndRemoved) {
// The newly added display is not a primary yet.
added_display_id = observer.GetDisplay().id();
- EXPECT_NE(platform_screen->GetPrimaryDisplay().id(), added_display_id);
+ EXPECT_NE(platform_screen_->GetPrimaryDisplay().id(), added_display_id);
// Make sure the geometry changes are sent by syncing one more time again.
Sync();
- int64_t old_primary_display_id = platform_screen->GetPrimaryDisplay().id();
+ int64_t old_primary_display_id = platform_screen_->GetPrimaryDisplay().id();
output_manager_->RemoveWaylandOutput(old_primary_display_id);
// Ensure that previously added display is now a primary one.
- EXPECT_EQ(platform_screen->GetPrimaryDisplay().id(), added_display_id);
+ EXPECT_EQ(platform_screen_->GetPrimaryDisplay().id(), added_display_id);
// Ensure that the removed display was the one, which was a primary display.
EXPECT_EQ(observer.GetDisplay().id(), old_primary_display_id);
+
+ platform_screen_->RemoveObserver(&observer);
}
TEST_P(WaylandScreenTest, OutputPropertyChanges) {
- std::unique_ptr<WaylandScreen> platform_screen =
- output_manager_->CreateWaylandScreen();
TestDisplayObserver observer;
- platform_screen->AddObserver(&observer);
+ platform_screen_->AddObserver(&observer);
const gfx::Rect new_rect(0, 0, 800, 600);
wl_output_send_geometry(output_->resource(), new_rect.x(), new_rect.y(),
@@ -156,6 +170,7 @@ TEST_P(WaylandScreenTest, OutputPropertyChanges) {
0 /* transform */);
wl_output_send_mode(output_->resource(), WL_OUTPUT_MODE_CURRENT,
new_rect.width(), new_rect.height(), 0 /* refresh */);
+ wl_output_send_done(output_->resource());
Sync();
@@ -167,6 +182,7 @@ TEST_P(WaylandScreenTest, OutputPropertyChanges) {
const float new_scale_value = 2.0f;
wl_output_send_scale(output_->resource(), new_scale_value);
+ wl_output_send_done(output_->resource());
Sync();
@@ -175,6 +191,61 @@ TEST_P(WaylandScreenTest, OutputPropertyChanges) {
display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
EXPECT_EQ(observer.GetDisplay().device_scale_factor(), new_scale_value);
+
+ platform_screen_->RemoveObserver(&observer);
+}
+
+TEST_P(WaylandScreenTest, GetAcceleratedWidgetAtScreenPoint) {
+ // If there is no focused window (focus is set whenever a pointer enters any
+ // of the windows), there must be kNullAcceleratedWidget returned. There is no
+ // real way to determine what window is located on a certain screen point in
+ // Wayland.
+ gfx::AcceleratedWidget widget_at_screen_point =
+ platform_screen_->GetAcceleratedWidgetAtScreenPoint(gfx::Point(10, 10));
+ EXPECT_EQ(widget_at_screen_point, gfx::kNullAcceleratedWidget);
+
+ // Set a focus to the main window. Now, that focused window must be returned.
+ window_->set_pointer_focus(true);
+ widget_at_screen_point =
+ platform_screen_->GetAcceleratedWidgetAtScreenPoint(gfx::Point(10, 10));
+ EXPECT_EQ(widget_at_screen_point, window_->GetWidget());
+
+ // Getting a widget at a screen point outside its bounds, must result in a
+ // null widget.
+ const gfx::Rect window_bounds = window_->GetBounds();
+ widget_at_screen_point = platform_screen_->GetAcceleratedWidgetAtScreenPoint(
+ gfx::Point(window_bounds.width() + 1, window_bounds.height() + 1));
+ EXPECT_EQ(widget_at_screen_point, gfx::kNullAcceleratedWidget);
+
+ MockPlatformWindowDelegate delegate;
+ std::unique_ptr<WaylandWindow> menu_window =
+ CreateWaylandWindowWithProperties(
+ gfx::Rect(window_->GetBounds().width() - 10,
+ window_->GetBounds().height() - 10, 100, 100),
+ PlatformWindowType::kPopup, window_->GetWidget(), &delegate);
+
+ Sync();
+
+ // Imagine the mouse enters a menu window, which is located on top of the main
+ // window, and gathers focus.
+ window_->set_pointer_focus(false);
+ menu_window->set_pointer_focus(true);
+ widget_at_screen_point =
+ platform_screen_->GetAcceleratedWidgetAtScreenPoint(gfx::Point(
+ menu_window->GetBounds().x() + 1, menu_window->GetBounds().y() + 1));
+ EXPECT_EQ(widget_at_screen_point, menu_window->GetWidget());
+
+ // Whenever a mouse pointer leaves the menu window, the accelerated widget
+ // of that focused window must be returned.
+ window_->set_pointer_focus(true);
+ menu_window->set_pointer_focus(false);
+ widget_at_screen_point =
+ platform_screen_->GetAcceleratedWidgetAtScreenPoint(gfx::Point(0, 0));
+ EXPECT_EQ(widget_at_screen_point, window_->GetWidget());
+
+ // Reset the focus to avoid crash on dtor as long as there is no real pointer
+ // object.
+ window_->set_pointer_focus(false);
}
INSTANTIATE_TEST_CASE_P(XdgVersionV5Test,
diff --git a/chromium/ui/ozone/platform/wayland/wayland_test.h b/chromium/ui/ozone/platform/wayland/wayland_test.h
index 26f44a50b93..7c2109062ca 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_test.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_test.h
@@ -7,7 +7,7 @@
#include "base/message_loop/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ui_features.h"
+#include "ui/base/buildflags.h"
#include "ui/ozone/platform/wayland/fake_server.h"
#include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
diff --git a/chromium/ui/ozone/platform/wayland/wayland_touch.cc b/chromium/ui/ozone/platform/wayland/wayland_touch.cc
index 9052eaf09b3..d30bc7342d9 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_touch.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_touch.cc
@@ -8,7 +8,7 @@
#include <wayland-client.h>
#include "base/files/scoped_file.h"
-#include "ui/base/ui_features.h"
+#include "ui/base/buildflags.h"
#include "ui/events/event.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
#include "ui/ozone/platform/wayland/wayland_window.h"
diff --git a/chromium/ui/ozone/platform/wayland/wayland_window.cc b/chromium/ui/ozone/platform/wayland/wayland_window.cc
index 3c3a59001ac..eeb3068c15e 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_window.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_window.cc
@@ -92,7 +92,7 @@ WaylandWindow::~WaylandWindow() {
}
PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
- connection_->RemoveWindow(surface_.id());
+ connection_->RemoveWindow(GetWidget());
if (parent_window_)
parent_window_->set_child_window(nullptr);
@@ -140,13 +140,19 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
connection_->ScheduleFlush();
- connection_->AddWindow(surface_.id(), this);
+ connection_->AddWindow(GetWidget(), this);
PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
- delegate_->OnAcceleratedWidgetAvailable(surface_.id());
+ delegate_->OnAcceleratedWidgetAvailable(GetWidget());
return true;
}
+gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
+ if (!surface_)
+ return gfx::kNullAcceleratedWidget;
+ return surface_.id();
+}
+
void WaylandWindow::CreateXdgPopup() {
if (bounds_.IsEmpty())
return;
diff --git a/chromium/ui/ozone/platform/wayland/wayland_window.h b/chromium/ui/ozone/platform/wayland/wayland_window.h
index 7e54fb49f11..a3ab6c47704 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_window.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_window.h
@@ -52,6 +52,8 @@ class WaylandWindow : public PlatformWindow,
XDGSurfaceWrapper* xdg_surface() const { return xdg_surface_.get(); }
XDGPopupWrapper* xdg_popup() const { return xdg_popup_.get(); }
+ gfx::AcceleratedWidget GetWidget() const;
+
// Apply the bounds specified in the most recent configure event. This should
// be called after processing all pending events in the wayland connection.
void ApplyPendingBounds();
diff --git a/chromium/ui/ozone/public/ozone_platform.cc b/chromium/ui/ozone/public/ozone_platform.cc
index d9c531079cf..aa2e5351d3b 100644
--- a/chromium/ui/ozone/public/ozone_platform.cc
+++ b/chromium/ui/ozone/public/ozone_platform.cc
@@ -39,8 +39,6 @@ OzonePlatform::OzonePlatform() {
GetOzoneInstanceLock().AssertAcquired();
DCHECK(!g_instance) << "There should only be a single OzonePlatform.";
g_instance = this;
- g_platform_initialized_ui = false;
- g_platform_initialized_gpu = false;
}
OzonePlatform::~OzonePlatform() = default;
@@ -50,11 +48,14 @@ void OzonePlatform::InitializeForUI(const InitParams& args) {
EnsureInstance();
if (g_platform_initialized_ui)
return;
- g_platform_initialized_ui = true;
g_instance->InitializeUI(args);
// This is deliberately created after initializing so that the platform can
// create its own version of DDM.
DeviceDataManager::CreateInstance();
+ {
+ base::AutoLock lock(GetOzoneInstanceLock());
+ g_platform_initialized_ui = true;
+ }
auto& instance_callback = GetInstanceCallback();
if (instance_callback)
std::move(instance_callback).Run(g_instance);
@@ -104,7 +105,7 @@ void OzonePlatform::RegisterStartupCallback(StartupCallback callback) {
OzonePlatform* inst = nullptr;
{
base::AutoLock lock(GetOzoneInstanceLock());
- if (!g_instance || !g_platform_initialized_ui) {
+ if (!g_platform_initialized_ui) {
auto& instance_callback = GetInstanceCallback();
instance_callback = std::move(callback);
return;
@@ -122,6 +123,11 @@ std::unique_ptr<PlatformScreen> OzonePlatform::CreateScreen() {
return nullptr;
}
+PlatformClipboard* OzonePlatform::GetPlatformClipboard() {
+ // Platforms that support system clipboard must override this method.
+ return nullptr;
+}
+
bool OzonePlatform::IsNativePixmapConfigSupported(
gfx::BufferFormat format,
gfx::BufferUsage usage) const {
diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h
index ceb287245bd..b1ef7fa970c 100644
--- a/chromium/ui/ozone/public/ozone_platform.h
+++ b/chromium/ui/ozone/public/ozone_platform.h
@@ -11,10 +11,8 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
-#include "services/service_manager/public/cpp/bind_source_info.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "ui/gfx/buffer_types.h"
-#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/ozone_export.h"
namespace display {
@@ -40,6 +38,7 @@ class PlatformWindow;
class PlatformWindowDelegate;
class SurfaceFactoryOzone;
class SystemInputInjector;
+class PlatformClipboard;
struct PlatformWindowInitProperties;
@@ -148,6 +147,7 @@ class OZONE_EXPORT OzonePlatform {
virtual std::unique_ptr<display::NativeDisplayDelegate>
CreateNativeDisplayDelegate() = 0;
virtual std::unique_ptr<PlatformScreen> CreateScreen();
+ virtual PlatformClipboard* GetPlatformClipboard();
// Returns true if the specified buffer format is supported.
virtual bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
diff --git a/chromium/ui/ozone/public/clipboard_delegate.h b/chromium/ui/ozone/public/platform_clipboard.h
index f2dcbb3d34e..df5940924b1 100644
--- a/chromium/ui/ozone/public/clipboard_delegate.h
+++ b/chromium/ui/ozone/public/platform_clipboard.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_OZONE_PUBLIC_CLIPBOARD_DELEGATE_H_
-#define UI_OZONE_PUBLIC_CLIPBOARD_DELEGATE_H_
+#ifndef UI_OZONE_PUBLIC_PLATFORM_CLIPBOARD_H_
+#define UI_OZONE_PUBLIC_PLATFORM_CLIPBOARD_H_
#include <string>
#include <unordered_map>
@@ -15,11 +15,11 @@
namespace ui {
-// ClipboardDelegate is an interface that allows Ozone backends to exchange
+// PlatformClipboard is an interface that allows Ozone backends to exchange
// data with other applications on the host system. The most familiar use for
// it is handling copy and paste operations.
//
-class OZONE_BASE_EXPORT ClipboardDelegate {
+class OZONE_BASE_EXPORT PlatformClipboard {
public:
// DataMap is a map from "mime type" to associated data, whereas
// the data can be organized differently for each mime type.
@@ -75,4 +75,4 @@ class OZONE_BASE_EXPORT ClipboardDelegate {
} // namespace ui
-#endif // UI_OZONE_PUBLIC_CLIPBOARD_DELEGATE_H_
+#endif // UI_OZONE_PUBLIC_PLATFORM_CLIPBOARD_H_
diff --git a/chromium/ui/ozone/public/platform_window_surface.h b/chromium/ui/ozone/public/platform_window_surface.h
new file mode 100644
index 00000000000..73eeda026bb
--- /dev/null
+++ b/chromium/ui/ozone/public/platform_window_surface.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PUBLIC_PLATFORM_WINDOW_SURFACE_H_
+#define UI_OZONE_PUBLIC_PLATFORM_WINDOW_SURFACE_H_
+
+#include "ui/ozone/ozone_base_export.h"
+
+namespace ui {
+
+// Rendering and presentation API agnostic platform surface object.
+//
+// This object should be created prior to creation of a GLSurface,
+// VulkanSurface, or software surface that presents to a PlatformWindow.
+//
+// It is basically the Viz service version of PlatformWindow, and is intended to
+// contain the windowing system connection for a particular window's rendering
+// surface.
+//
+// However, currently it is only used by SkiaRenderer on Fuchsia and does
+// nothing in all other cases.
+//
+// TODO(spang): If we go this way, we should be consistent. You should have to
+// have a PlatformWindowSurface before building a GLSurface or software surface
+// as well.
+class OZONE_BASE_EXPORT PlatformWindowSurface {
+ public:
+ virtual ~PlatformWindowSurface() {}
+
+ // Note: GL & Vulkan surface are created through the GLOzone &
+ // VulkanImplementation interfaces, respectively.
+ //
+ // However, you must still create a PlatformWindowSurface and keep it alive in
+ // order to present.
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_PLATFORM_WINDOW_SURFACE_H_
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.cc b/chromium/ui/ozone/public/surface_factory_ozone.cc
index ea7fa8b6453..a12ec481e51 100644
--- a/chromium/ui/ozone/public/surface_factory_ozone.cc
+++ b/chromium/ui/ozone/public/surface_factory_ozone.cc
@@ -10,6 +10,7 @@
#include "gpu/vulkan/buildflags.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/ozone/public/overlay_surface.h"
+#include "ui/ozone/public/platform_window_surface.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
#if BUILDFLAG(ENABLE_VULKAN)
@@ -51,6 +52,12 @@ SurfaceFactoryOzone::CreateNativePixmapForVulkan(
}
#endif
+std::unique_ptr<PlatformWindowSurface>
+SurfaceFactoryOzone::CreatePlatformWindowSurface(
+ gfx::AcceleratedWidget widget) {
+ return nullptr;
+}
+
std::unique_ptr<OverlaySurface> SurfaceFactoryOzone::CreateOverlaySurface(
gfx::AcceleratedWidget widget) {
return nullptr;
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.h b/chromium/ui/ozone/public/surface_factory_ozone.h
index 4c4c0e767e8..6ac0ea495c4 100644
--- a/chromium/ui/ozone/public/surface_factory_ozone.h
+++ b/chromium/ui/ozone/public/surface_factory_ozone.h
@@ -36,6 +36,7 @@ namespace ui {
class SurfaceOzoneCanvas;
class OverlaySurface;
+class PlatformWindowSurface;
// The Ozone interface allows external implementations to hook into Chromium to
// provide a system specific implementation. The Ozone interface supports two
@@ -94,6 +95,11 @@ class OZONE_BASE_EXPORT SurfaceFactoryOzone {
VkImage* vk_image);
#endif
+ // Creates a rendering and presentation API agnostic surface for a platform
+ // window.
+ virtual std::unique_ptr<PlatformWindowSurface> CreatePlatformWindowSurface(
+ gfx::AcceleratedWidget window);
+
// Creates an overlay surface for a platform window.
virtual std::unique_ptr<OverlaySurface> CreateOverlaySurface(
gfx::AcceleratedWidget window);
diff --git a/chromium/ui/ozone/public/surface_ozone_canvas.h b/chromium/ui/ozone/public/surface_ozone_canvas.h
index 65f6de4b806..05577a98c20 100644
--- a/chromium/ui/ozone/public/surface_ozone_canvas.h
+++ b/chromium/ui/ozone/public/surface_ozone_canvas.h
@@ -32,13 +32,13 @@ class OZONE_BASE_EXPORT SurfaceOzoneCanvas {
virtual sk_sp<SkSurface> GetSurface() = 0;
// Attempts to resize the canvas to match the viewport size. After
- // resizing, the compositor must call GetCanvas() to get the next
- // canvas - this invalidates any previous canvas from GetCanvas().
+ // resizing, the compositor must call GetSurface() to get the next
+ // surface - this invalidates any previous surface from GetSurface().
virtual void ResizeCanvas(const gfx::Size& viewport_size) = 0;
- // Present the current canvas. After presenting, the compositor must
- // call GetCanvas() to get the next canvas - this invalidates any
- // previous canvas from GetCanvas().
+ // Present the current surface. After presenting, the compositor must
+ // call GetSurface() to get the next surface - this invalidates any
+ // previous surface from GetSurface().
//
// The implementation may assume that any pixels outside the damage
// rectangle are unchanged since the previous call to PresentCanvas().
diff --git a/chromium/ui/platform_window/BUILD.gn b/chromium/ui/platform_window/BUILD.gn
index efa50832393..482b2ff6645 100644
--- a/chromium/ui/platform_window/BUILD.gn
+++ b/chromium/ui/platform_window/BUILD.gn
@@ -29,7 +29,7 @@ source_set("platform_window") {
]
public_deps = [
- "//third_party/fuchsia-sdk/sdk:policy",
+ "//third_party/fuchsia-sdk/sdk:ui_policy",
"//third_party/fuchsia-sdk/sdk:zx",
]
}
diff --git a/chromium/ui/resources/default_100_percent/common/emoji_menu_item.png b/chromium/ui/resources/default_100_percent/common/emoji_menu_item.png
deleted file mode 100644
index a5750ab283e..00000000000
--- a/chromium/ui/resources/default_100_percent/common/emoji_menu_item.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/mac/menu_hierarchy_arrow.png b/chromium/ui/resources/default_100_percent/mac/menu_hierarchy_arrow.png
deleted file mode 100644
index 15475fbdcff..00000000000
--- a/chromium/ui/resources/default_100_percent/mac/menu_hierarchy_arrow.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/supervised_illustration_done.png b/chromium/ui/resources/default_100_percent/supervised_illustration_done.png
deleted file mode 100644
index d602b0fdf5e..00000000000
--- a/chromium/ui/resources/default_100_percent/supervised_illustration_done.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/supervised_illustration_start.png b/chromium/ui/resources/default_100_percent/supervised_illustration_start.png
deleted file mode 100644
index 99ed2a40d4b..00000000000
--- a/chromium/ui/resources/default_100_percent/supervised_illustration_start.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/emoji_menu_item.png b/chromium/ui/resources/default_200_percent/common/emoji_menu_item.png
deleted file mode 100644
index f490a52c25f..00000000000
--- a/chromium/ui/resources/default_200_percent/common/emoji_menu_item.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/mac/menu_hierarchy_arrow.png b/chromium/ui/resources/default_200_percent/mac/menu_hierarchy_arrow.png
deleted file mode 100644
index 715fcc817b1..00000000000
--- a/chromium/ui/resources/default_200_percent/mac/menu_hierarchy_arrow.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/supervised_illustration_done.png b/chromium/ui/resources/default_200_percent/supervised_illustration_done.png
deleted file mode 100644
index e76393e32de..00000000000
--- a/chromium/ui/resources/default_200_percent/supervised_illustration_done.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/supervised_illustration_start.png b/chromium/ui/resources/default_200_percent/supervised_illustration_start.png
deleted file mode 100644
index af12343d0cc..00000000000
--- a/chromium/ui/resources/default_200_percent/supervised_illustration_start.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_300_percent/common/emoji_menu_item.png b/chromium/ui/resources/default_300_percent/common/emoji_menu_item.png
deleted file mode 100644
index 10851aa55af..00000000000
--- a/chromium/ui/resources/default_300_percent/common/emoji_menu_item.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/ui_resources.grd b/chromium/ui/resources/ui_resources.grd
index 3eec9da09e1..2cd4db2b72c 100644
--- a/chromium/ui/resources/ui_resources.grd
+++ b/chromium/ui/resources/ui_resources.grd
@@ -108,7 +108,6 @@
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED" file="common/easy_unlock_unlocked.png" />
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED_HOVER" file="common/easy_unlock_unlocked_hover.png" />
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED_PRESSED" file="common/easy_unlock_unlocked_pressed.png" />
- <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="toolkit_views and not is_macosx">
diff --git a/chromium/ui/shell_dialogs/BUILD.gn b/chromium/ui/shell_dialogs/BUILD.gn
index bd4d92a194b..b12b5254b9c 100644
--- a/chromium/ui/shell_dialogs/BUILD.gn
+++ b/chromium/ui/shell_dialogs/BUILD.gn
@@ -45,6 +45,7 @@ jumbo_component("shell_dialogs") {
"//skia",
"//ui/base",
"//ui/strings",
+ "//url",
]
if (use_aura) {
diff --git a/chromium/ui/shell_dialogs/select_file_dialog.h b/chromium/ui/shell_dialogs/select_file_dialog.h
index e8a40882093..f8b7aea68e5 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog.h
+++ b/chromium/ui/shell_dialogs/select_file_dialog.h
@@ -141,7 +141,12 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
// NATIVE_PATH, the dialog creates a native replica of the non-native file
// and returns its path, so that the caller can use it without any
// difference than when it were local.
- enum AllowedPaths { ANY_PATH, NATIVE_PATH, NATIVE_OR_DRIVE_PATH };
+ enum AllowedPaths {
+ ANY_PATH,
+ NATIVE_PATH,
+ NATIVE_OR_DRIVE_PATH,
+ ANY_PATH_OR_URL
+ };
AllowedPaths allowed_paths;
};
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_mac.mm b/chromium/ui/shell_dialogs/select_file_dialog_mac.mm
index 29329c65f98..4851a771f93 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_mac.mm
+++ b/chromium/ui/shell_dialogs/select_file_dialog_mac.mm
@@ -19,6 +19,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#import "ui/base/cocoa/nib_loading.h"
+#include "ui/base/cocoa/remote_views_window.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/shell_dialogs/select_file_policy.h"
#include "ui/strings/grit/ui_strings.h"
@@ -147,6 +148,14 @@ void SelectFileDialogImpl::SelectFileImpl(
type == SELECT_EXISTING_FOLDER || type == SELECT_OPEN_FILE ||
type == SELECT_OPEN_MULTI_FILE || type == SELECT_SAVEAS_FILE);
NSWindow* owning_window = owning_native_window.GetNativeNSWindow();
+ // TODO(https://crbug.com/913303): The select file dialog's interface to
+ // Cocoa should be wrapped in a mojo interface in order to allow instantiating
+ // across processes. As a temporary solution, raise the remote windows'
+ // transparent in-process window to the front.
+ if (ui::IsWindowUsingRemoteViews(owning_window)) {
+ [owning_window makeKeyAndOrderFront:nil];
+ [owning_window setLevel:NSModalPanelWindowLevel];
+ }
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 7b15ec2c986..e6a99e4051f 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
+++ b/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
@@ -9,8 +9,8 @@
#include "base/files/file_util.h"
#import "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
-#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -382,7 +382,7 @@ TEST_F(SelectFileDialogMacTest, SelectionType) {
HAS_ACCESSORY_VIEW | PICK_FILES | MULTIPLE_SELECTION, "Open"},
};
- for (size_t i = 0; i < arraysize(test_cases); i++) {
+ for (size_t i = 0; i < base::size(test_cases); i++) {
SCOPED_TRACE(
base::StringPrintf("i=%lu file_dialog_type=%d", i, test_cases[i].type));
args.type = test_cases[i].type;
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_unittest.cc b/chromium/ui/shell_dialogs/select_file_dialog_unittest.cc
index e2831868a51..57d5f5fcfbc 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_unittest.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_unittest.cc
@@ -4,7 +4,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/shell_dialogs/select_file_dialog.h"
@@ -101,7 +101,7 @@ TEST(ShellDialogs, ShortenFileNameIfNeeded) {
"jklmnopqrstuvwxyz1234abcdefghijklmnopqrstuvwxyz1234ab"
"cdefghijklmnopqrstuvwxyz1234ab.abcdefghijkl")}};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
base::FilePath input =
base::FilePath(test_cases[i].input).NormalizePathSeparators();
base::FilePath output =
diff --git a/chromium/ui/shell_dialogs/selected_file_info.cc b/chromium/ui/shell_dialogs/selected_file_info.cc
index 054c511e816..852eda6d000 100644
--- a/chromium/ui/shell_dialogs/selected_file_info.cc
+++ b/chromium/ui/shell_dialogs/selected_file_info.cc
@@ -15,6 +15,14 @@ SelectedFileInfo::SelectedFileInfo(const base::FilePath& in_file_path,
display_name = in_file_path.BaseName().value();
}
+SelectedFileInfo::SelectedFileInfo(const SelectedFileInfo& other) = default;
+SelectedFileInfo::SelectedFileInfo(SelectedFileInfo&& other) = default;
+
SelectedFileInfo::~SelectedFileInfo() {}
+SelectedFileInfo& SelectedFileInfo::operator=(const SelectedFileInfo& other) =
+ default;
+SelectedFileInfo& SelectedFileInfo::operator=(SelectedFileInfo&& other) =
+ default;
+
} // namespace ui
diff --git a/chromium/ui/shell_dialogs/selected_file_info.h b/chromium/ui/shell_dialogs/selected_file_info.h
index a1789c97038..89de4e2f62e 100644
--- a/chromium/ui/shell_dialogs/selected_file_info.h
+++ b/chromium/ui/shell_dialogs/selected_file_info.h
@@ -8,8 +8,10 @@
#include <vector>
#include "base/files/file_path.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "ui/shell_dialogs/shell_dialogs_export.h"
+#include "url/gurl.h"
namespace ui {
@@ -31,10 +33,20 @@ struct SHELL_DIALOGS_EXPORT SelectedFileInfo {
// |path| is used for displaying.
base::FilePath::StringType display_name;
+ // If set, this URL may be used to access the file. If the user is capable of
+ // using a URL to access the file, it should be used in preference to
+ // |local_path|.
+ base::Optional<GURL> url;
+
SelectedFileInfo();
SelectedFileInfo(const base::FilePath& in_file_path,
const base::FilePath& in_local_path);
+ SelectedFileInfo(const SelectedFileInfo& other);
+ SelectedFileInfo(SelectedFileInfo&& other);
~SelectedFileInfo();
+
+ SelectedFileInfo& operator=(const SelectedFileInfo& other);
+ SelectedFileInfo& operator=(SelectedFileInfo&& other);
};
} // namespace ui
diff --git a/chromium/ui/strings/translations/ui_strings_am.xtb b/chromium/ui/strings/translations/ui_strings_am.xtb
index a40952008cb..af2afc3909b 100644
--- a/chromium/ui/strings/translations/ui_strings_am.xtb
+++ b/chromium/ui/strings/translations/ui_strings_am.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 ቀን በፊት}one{# ቀኖች በፊት}other{# ቀኖች በፊት}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{ከ1 ደቂቃ በፊት}one{ከ# ደቂቃዎች በፊት}other{ከ# ደቂቃዎች በፊት}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1ደ}one{#ደ}other{#ደ}}</translation>
+<translation id="1181037720776840403">አስወግድ</translation>
<translation id="1243314992276662751">ስቀል</translation>
<translation id="1269641567813814718">ማሸነፍ</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">ዝቅዝቅ ቀስት</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ቀን}one{# ቀኖች}other{# ቀኖች}}</translation>
<translation id="335581015389089642">ንግግር</translation>
+<translation id="3462241349431650993">ይህን የጥቆማ ሐሳብ መደበቅ ከእርስዎ መለያ ላይ ወደ ሁሉም የእርስዎ መሣሪያዎች ዳግመኛ እንዳይታይ ያደርገዋል።</translation>
<translation id="3479552764303398839">አሁን አይደለም</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ቀን ቀርቷል}one{# ቀኖች ቀርቷል}other{# ቀኖች ቀርተዋል}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">«<ph name="LOOKUP_STRING" />»ን ፈልግ</translation>
<translation id="364720409959344976">የሚሰቀል ዓቃፊ ይምረጡ</translation>
<translation id="3660179305079774227">የላይ ቀስት</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{ከ1 ሰከንድ በፊት}one{ከ# ሰከንዶች በፊት}other{ከ# ሰከንዶች በፊት}}</translation>
<translation id="654149438358937226">ሁሉንም ማሳወቂያዎች አግድ</translation>
<translation id="6567071839949112727">ዘር ማንዘርን ጠቅ አድርግ</translation>
+<translation id="6578407462441924264">ያልተሰየመ</translation>
<translation id="6612467943526193239">ከመቃኘት ለመውጣት Escን ይጫኑ።</translation>
<translation id="6620110761915583480">ፋይል አስቀምጥ</translation>
<translation id="6699343763173986273">የሚዲያ ቀጣይ ትራክ</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 ሰዓት በፊት}one{# ሰዓቶች በፊት}other{# ሰዓቶች በፊት}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 ሰከንድ ቀርቷል}one{# ሰከንዶች ቀርቷል}other{# ሰከንዶች ቀርተዋል}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />፣ ራስሰር ሙላ</translation>
<translation id="815598010540052116">ወደ ታች ሸብልል</translation>
<translation id="8179976553408161302">አስገባ</translation>
<translation id="8210608804940886430">ወደታች አንቀሳቅስ</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">አመልክት</translation>
<translation id="8393700583063109961">መልዕክት ይላኩ</translation>
<translation id="8394908167088220973">ሚዲያ አጫውት/ለአፍታ አቁም</translation>
+<translation id="8420205633584771378">ይህ የአስተያየት ጥቆማ ይወገድ?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1ዓ}one{#ዓ}other{#ዓ}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> ፋይል(.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> ኪባ/ሰ</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">የተመለስ አዝራር</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> ኪባ</translation>
<translation id="9002566407876343676">ክፈት</translation>
-<translation id="9038489124413477075">ያልተሰየመ አቃፊ</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 ሰከን}one{# ሰከን}other{# ሰከን}}</translation>
<translation id="9059834730836941392">ማሳወቂያን ሰብስብ</translation>
<translation id="9150735707954472829">ትር</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ar.xtb b/chromium/ui/strings/translations/ui_strings_ar.xtb
index 80c5211bd48..ddc657d4eae 100644
--- a/chromium/ui/strings/translations/ui_strings_ar.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ar.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{قبل يوم واحد}zero{قبل # من الأيام}two{قبل يومين (#)}few{قبل # أيام}many{قبل # يومًا}other{قبل # من الأيام}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{قبل دقيقة واحدة}zero{قبل # دقيقة}two{قبل دقيقتين (#)}few{قبل # دقائق}many{قبل # دقيقة}other{قبل # دقيقة}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{دقيقة واحدة}zero{# دقيقة}two{دقيقتان (#)}few{# دقائق}many{# دقيقة}other{# دقيقة}}</translation>
+<translation id="1181037720776840403">إزالة</translation>
<translation id="1243314992276662751">تحميل</translation>
<translation id="1269641567813814718">الفوز</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">مفتاح سهم إلى أسفل</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{يوم واحد}zero{# من الأيام}two{يومان (#)}few{# أيام}many{# يومًا}other{# من الأيام}}</translation>
<translation id="335581015389089642">الحديث</translation>
+<translation id="3462241349431650993">لن يؤدي إخفاء هذا الاقتراح إلى عرضه مرة أخرى من حسابك على جميع أجهزتك.</translation>
<translation id="3479552764303398839">ليس الآن</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{يتبقى يوم واحد}zero{يتبقى عدد # من الأيام}two{يتبقى يومان (#)}few{يتبقى # أيام}many{يتبقى # يومًا}other{يتبقى # من الأيام}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">البحث عن "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">حدد مجلدًا للتحميل</translation>
<translation id="3660179305079774227">مفتاح سهم إلى أعلى</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{قبل ثانية واحدة}zero{قبل # ثانية}two{قبل ثانيتين (#)}few{قبل # ثوانٍ}many{قبل # ثانية}other{قبل # ثانية}}</translation>
<translation id="654149438358937226">حظر جميع الإشعارات</translation>
<translation id="6567071839949112727">النقر على العنصر الأصل</translation>
+<translation id="6578407462441924264">بدون اسم</translation>
<translation id="6612467943526193239">‏للخروج من المعايرة، اضغط على Esc.</translation>
<translation id="6620110761915583480">حفظ الملف</translation>
<translation id="6699343763173986273">المقطع الصوتي التالي للوسائط</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{قبل ساعة واحدة}zero{قبل # من الساعات}two{قبل ساعتين (#)}few{قبل # ساعات}many{قبل # ساعة}other{قبل # من الساعات}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{يتبقى ثانية واحدة}zero{يتبقى # من الثواني}two{يتبقى ثانيتان (#)}few{يتبقى # ثوانٍ}many{يتبقى # ثانية}other{يتبقى # من الثواني}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />، الإكمال التلقائي</translation>
<translation id="815598010540052116">التمرير إلى أسفل</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">صفحة إلى أسفل</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">الاختيار</translation>
<translation id="8393700583063109961">إرسال رسالة</translation>
<translation id="8394908167088220973">تشغيل/إيقاف الوسائط</translation>
+<translation id="8420205633584771378">هل تريد إزالة هذا الاقتراح؟</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{عام واحد}zero{# عام}two{عامان (#)}few{# أعوام}many{# عامًا}other{# عام}}</translation>
<translation id="8602707065186045623">ملف <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> كيلوبايت/ثانية</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">زر الرجوع</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> كيلوبايت</translation>
<translation id="9002566407876343676">الفتح</translation>
-<translation id="9038489124413477075">مجلد بدون اسم</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{ثانية واحدة}zero{# ثانية}two{ثانيتان (#)}few{# ثوانٍ}many{# ثانية}other{# من الثواني}}</translation>
<translation id="9059834730836941392">تصغير الإشعار</translation>
<translation id="9150735707954472829">علامة تبويب</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bg.xtb b/chromium/ui/strings/translations/ui_strings_bg.xtb
index 3e831578c26..bfada751463 100644
--- a/chromium/ui/strings/translations/ui_strings_bg.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bg.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Преди 1 ден}other{Преди # дни}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Преди 1 минута}other{Преди # минути}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 мин}other{# мин}}</translation>
+<translation id="1181037720776840403">Премахване</translation>
<translation id="1243314992276662751">Качване</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Стрелка надолу</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ден}other{# дни}}</translation>
<translation id="335581015389089642">Speech</translation>
+<translation id="3462241349431650993">При скриване на това предложение то няма да се показва повече в профила ви на никое от устройствата ви.</translation>
<translation id="3479552764303398839">Не сега</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Остава 1 ден}other{Остават # дни}}</translation>
+<translation id="3608915363409716668">Над <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Търсене на „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Избиране на папка за качване</translation>
<translation id="3660179305079774227">Стрелка нагоре</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Преди 1 секунда}other{Преди # секунди}}</translation>
<translation id="654149438358937226">Блокиране на всички известия</translation>
<translation id="6567071839949112727">кликване върху елемента предшественик</translation>
+<translation id="6578407462441924264">Без име</translation>
<translation id="6612467943526193239">За изход от калибрирането натиснете Esc.</translation>
<translation id="6620110761915583480">Запазване на файл</translation>
<translation id="6699343763173986273">Мултимедия, следващият запис</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Преди 1 час}other{Преди # часа}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Остава 1 сек}other{Остават # сек}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, автоматично довършване</translation>
<translation id="815598010540052116">Превъртане надолу</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Страница надолу</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">отмятане</translation>
<translation id="8393700583063109961">Изпратете съобщение</translation>
<translation id="8394908167088220973">Мултимедия, пускане/пауза</translation>
+<translation id="8420205633584771378">Да се премахне ли това предложение?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 г.}other{# г.}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> файл (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> КБ/сек</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Бутон за връщане назад</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KБ</translation>
<translation id="9002566407876343676">отварям</translation>
-<translation id="9038489124413477075">Папка без име</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 сек}other{# сек}}</translation>
<translation id="9059834730836941392">Свиване на известието</translation>
<translation id="9150735707954472829">Раздел</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bn.xtb b/chromium/ui/strings/translations/ui_strings_bn.xtb
index 295ac2ef66c..1f7f35da0aa 100644
--- a/chromium/ui/strings/translations/ui_strings_bn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bn.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{১ দিন পূর্বে}one{# দিন পূর্বে}other{# দিন পূর্বে}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{১ মিনিট আগে}one{# মিনিট আগে}other{# মিনিট আগে}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{১ মিনিট}one{# মিনিট}other{# মিনিট}}</translation>
+<translation id="1181037720776840403">সরান</translation>
<translation id="1243314992276662751">আপলোড</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Down Arrow</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{১ দিন}one{# দিন}other{# দিন}}</translation>
<translation id="335581015389089642">স্পিচ</translation>
+<translation id="3462241349431650993">এই সাজেশনটি লুকালে সমস্ত ডিভাইস জুড়ে আপনার অ্যাকাউন্টে আর দেখা যাবে না।</translation>
<translation id="3479552764303398839">এখনই নয়</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{১ দিন বাকি}one{# দিন বাকি}other{# দিন বাকি}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” খুঁজে দেখুন</translation>
<translation id="364720409959344976">আপলোড করার জন্য ফোল্ডার বেছে নিন</translation>
<translation id="3660179305079774227">Up Arrow</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{১ সেকেন্ড আগে}one{# সেকেন্ড আগে}other{# সেকেন্ড আগে}}</translation>
<translation id="654149438358937226">সমস্ত বিজ্ঞপ্তি ব্লক করুন</translation>
<translation id="6567071839949112727">এটি সম্পর্কিত একটি পুরানো আইটেমে ক্লিক করুন</translation>
+<translation id="6578407462441924264">নামবিহীন</translation>
<translation id="6612467943526193239">ক্রমাঙ্কন থেকে বেরিয়ে যেতে Esc টিপুন।</translation>
<translation id="6620110761915583480">ফাইল সেভ করুন</translation>
<translation id="6699343763173986273">মিডিয়া পরবর্তী ট্র্যাক</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{১ ঘণ্টা পূর্বে}one{# ঘণ্টা পূর্বে}other{# ঘণ্টা পূর্বে}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{১ সেকেন্ড বাকি}one{# সেকেন্ড বাকি}other{# সেকেন্ড বাকি}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, নিজে থেকে সম্পূর্ন করা</translation>
<translation id="815598010540052116">নিচে স্ক্রোল করুন</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">পৃষ্ঠা উপরে</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">চেক করুন</translation>
<translation id="8393700583063109961">বার্তা পাঠান</translation>
<translation id="8394908167088220973">মিডিয়া প্লে করুন/বিরতি</translation>
+<translation id="8420205633584771378">সাজেশনটি সরাতে চান?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{১ বছর}one{# বছর}other{# বছর}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> ফাইল (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">ফিরে যাওয়ার বোতাম</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">খুলুন</translation>
-<translation id="9038489124413477075">নামবিহীন ফোল্ডার</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{১ সেকেন্ড}one{# সেকেন্ড}other{# সেকেন্ড}}</translation>
<translation id="9059834730836941392">বিজ্ঞপ্তি সঙ্কুচিত করুন</translation>
<translation id="9150735707954472829">ট্যাব</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ca.xtb b/chromium/ui/strings/translations/ui_strings_ca.xtb
index 19f60bfd926..ad968d49981 100644
--- a/chromium/ui/strings/translations/ui_strings_ca.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ca.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{fa 1 dia}other{fa # dies}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Fa 1 minut}other{Fa # minuts}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 m}other{# m}}</translation>
+<translation id="1181037720776840403">Suprimeix</translation>
<translation id="1243314992276662751">Penja</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Fletxa avall</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dia}other{# dies}}</translation>
<translation id="335581015389089642">Veu</translation>
+<translation id="3462241349431650993">Si amagues aquest suggeriment, no es tornarà a mostrar des del teu del compte en tots els dispositius.</translation>
<translation id="3479552764303398839">Ara no</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dia restant}other{# dies restants}}</translation>
+<translation id="3608915363409716668">Més de <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Cerca "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Selecció d'una carpeta per penjar</translation>
<translation id="3660179305079774227">Fletxa amunt</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Fa 1 segon}other{Fa # segons}}</translation>
<translation id="654149438358937226">Bloqueja totes les notificacions</translation>
<translation id="6567071839949112727">fes clic a l'antecedent</translation>
+<translation id="6578407462441924264">Sense nom</translation>
<translation id="6612467943526193239">Prem Esc per sortir del calibratge.</translation>
<translation id="6620110761915583480">Desa el fitxer</translation>
<translation id="6699343763173986273">Fitxer multimèdia: pista següent</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{fa 1 hora}other{fa # hores}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 s restant}other{# s restants}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, compleció automàtica</translation>
<translation id="815598010540052116">Desplaçament avall</translation>
<translation id="8179976553408161302">Retorn</translation>
<translation id="8210608804940886430">Av Pàg</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">marca</translation>
<translation id="8393700583063109961">Envia el missatge</translation>
<translation id="8394908167088220973">Fitxer multimèdia: reprodueix/posa en pausa</translation>
+<translation id="8420205633584771378">Vols suprimir aquest suggeriment?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 a}other{# a}}</translation>
<translation id="8602707065186045623">Fitxer <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Botó Enrere</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">obrir</translation>
-<translation id="9038489124413477075">Carpeta sense nom</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}other{# s}}</translation>
<translation id="9059834730836941392">Replega la notificació</translation>
<translation id="9150735707954472829">Pestanya</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_cs.xtb b/chromium/ui/strings/translations/ui_strings_cs.xtb
index 883e5ab2a34..669689430c1 100644
--- a/chromium/ui/strings/translations/ui_strings_cs.xtb
+++ b/chromium/ui/strings/translations/ui_strings_cs.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Před 1 dnem}few{Před # dny}many{Před # dne}other{Před # dny}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{před minutou}few{před # minutami}many{před # minuty}other{před # minutami}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}few{# min}many{# min}other{# min}}</translation>
+<translation id="1181037720776840403">Odebrat</translation>
<translation id="1243314992276662751">Nahrát</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Klávesa Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Pokud tento návrh skryjete, již se vám ve vašem účtu na žádném z vašich zařízení znovu nezobrazí.</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="3608915363409716668">&gt; <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Vyhledat „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Vyberte složku pro nahrávání</translation>
<translation id="3660179305079774227">Klávesa šipka nahoru</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{před sekundou}few{před # sekundami}many{před # sekundy}other{před # sekundami}}</translation>
<translation id="654149438358937226">Blokovat všechna oznámení</translation>
<translation id="6567071839949112727">kliknutí na nadřazený prvek</translation>
+<translation id="6578407462441924264">Bez názvu</translation>
<translation id="6612467943526193239">Kalibraci ukončíte stisknutím klávesy Esc.</translation>
<translation id="6620110761915583480">Uložit soubor</translation>
<translation id="6699343763173986273">Média – další skladba</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Před 1 hodinou}few{Před # hodinami}many{Před # hodiny}other{Před # hodinami}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Zbývá 1 s}few{Zbývají # s}many{Zbývá # s}other{Zbývá # s}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automatické doplnění</translation>
<translation id="815598010540052116">Posuv dolů</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Klávesa PageDown</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">zaškrtnout</translation>
<translation id="8393700583063109961">Odeslat zprávu</translation>
<translation id="8394908167088220973">Média – přehrát/pozastavit</translation>
+<translation id="8420205633584771378">Odstranit tento návrh?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 r}few{# r}many{# r}other{# r}}</translation>
<translation id="8602707065186045623">Soubor <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Tlačítko Zpět</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<translation id="9002566407876343676">otevřít</translation>
-<translation id="9038489124413477075">Nepojmenovaná složka</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}few{# s}many{# s}other{# s}}</translation>
<translation id="9059834730836941392">Sbalit oznámení</translation>
<translation id="9150735707954472829">Karta</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_da.xtb b/chromium/ui/strings/translations/ui_strings_da.xtb
index 18f74d5fc1f..4ff99670e0b 100644
--- a/chromium/ui/strings/translations/ui_strings_da.xtb
+++ b/chromium/ui/strings/translations/ui_strings_da.xtb
@@ -5,6 +5,7 @@
<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>
+<translation id="1181037720776840403">Fjern</translation>
<translation id="1243314992276662751">Upload</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Hvis du skjuler dette forslag, vises det ikke på din konto på nogen af dine enheder.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Slå "<ph name="LOOKUP_STRING" />" op</translation>
<translation id="364720409959344976">Vælg den mappe, der skal uploades</translation>
<translation id="3660179305079774227">Pil opad</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{For 1 sekund siden}one{For # sekund siden}other{For # sekunder siden}}</translation>
<translation id="654149438358937226">Bloker alle notifikationer</translation>
<translation id="6567071839949112727">klik på overordnet element</translation>
+<translation id="6578407462441924264">Uden navn</translation>
<translation id="6612467943526193239">Tryk på Esc for at afslutte kalibreringen.</translation>
<translation id="6620110761915583480">Gem fil</translation>
<translation id="6699343763173986273">Medie: Næste nummer</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{for 1 time siden}one{for # time siden}other{for # timer siden}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sek. tilbage}one{# sek. tilbage}other{# sek. tilbage}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, autofuldfør</translation>
<translation id="815598010540052116">Scroll Down</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Side ned</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">markér</translation>
<translation id="8393700583063109961">Send en besked</translation>
<translation id="8394908167088220973">Medie: Afspil/Pause</translation>
+<translation id="8420205633584771378">Vil du fjerne dette forslag?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 år}one{# år}other{# år}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> Fil (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB/sek.</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Knappen Tilbage</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<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 notifikation</translation>
<translation id="9150735707954472829">Fane</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_de.xtb b/chromium/ui/strings/translations/ui_strings_de.xtb
index 1eee1ee7513..93c469c5851 100644
--- a/chromium/ui/strings/translations/ui_strings_de.xtb
+++ b/chromium/ui/strings/translations/ui_strings_de.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 Tag her}other{# Tage her}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Vor 1 Minute}other{Vor # Minuten}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}other{# min}}</translation>
+<translation id="1181037720776840403">Entfernen</translation>
<translation id="1243314992276662751">Hochladen</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Abwärtspfeil</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 Tag}other{# Tage}}</translation>
<translation id="335581015389089642">Sprachausgabe</translation>
+<translation id="3462241349431650993">Wenn Sie diesen Vorschlag ausblenden, wird er für Ihr Konto nicht mehr angezeigt, unabhängig vom Gerät.</translation>
<translation id="3479552764303398839">Jetzt nicht</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 Tag übrig}other{# Tage übrig}}</translation>
+<translation id="3608915363409716668">&gt;<ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">"<ph name="LOOKUP_STRING" />" nachschlagen</translation>
<translation id="364720409959344976">Ordner zum Hochladen auswählen</translation>
<translation id="3660179305079774227">Aufwärtspfeil</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Vor 1 Sekunde}other{Vor # Sekunden}}</translation>
<translation id="654149438358937226">Alle Benachrichtigungen blockieren</translation>
<translation id="6567071839949112727">Auf Vorgängerelement klicken</translation>
+<translation id="6578407462441924264">Unbenannt</translation>
<translation id="6612467943526193239">Zum Abbrechen der Kalibrierung ESC drücken.</translation>
<translation id="6620110761915583480">Datei speichern</translation>
<translation id="6699343763173986273">Medien – nächster Titel</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 Stunde her}other{# Stunden her}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 Sek. übrig}other{# Sek. übrig}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automatische Vervollständigung</translation>
<translation id="815598010540052116">Nach unten blättern</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Nach unten</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">auswählen</translation>
<translation id="8393700583063109961">Nachricht senden</translation>
<translation id="8394908167088220973">Medien – Wiedergabe/Pause</translation>
+<translation id="8420205633584771378">Diesen Vorschlag entfernen?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 Jahr}other{# Jahre}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" />-Datei (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Schaltfläche "Zurück"</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">Öffnen</translation>
-<translation id="9038489124413477075">Unbenannter Ordner</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 Sek.}other{# Sek.}}</translation>
<translation id="9059834730836941392">Benachrichtigung minimieren</translation>
<translation id="9150735707954472829">Tab</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_el.xtb b/chromium/ui/strings/translations/ui_strings_el.xtb
index 1084c065de7..9695c5d04e6 100644
--- a/chromium/ui/strings/translations/ui_strings_el.xtb
+++ b/chromium/ui/strings/translations/ui_strings_el.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Πριν από 1 ημέρα}other{Πριν από # ημέρες}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Πριν από 1 λεπτό}other{Πριν από # λεπτά}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1λ.}other{#λ.}}</translation>
+<translation id="1181037720776840403">Κατάργηση</translation>
<translation id="1243314992276662751">Μεταφόρτωση</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Κάτω βέλος</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ημέρα}other{# ημέρες}}</translation>
<translation id="335581015389089642">Ομιλία</translation>
+<translation id="3462241349431650993">Εάν κάνετε απόκρυψη σε αυτήν την πρόταση, δεν θα εμφανιστεί ξανά από τον λογαριασμό σας σε όλες τις συσκευές σας.</translation>
<translation id="3479552764303398839">Όχι τώρα</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Απομένει 1 ημέρα}other{Απομένουν # ημέρες}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Αναζήτηση "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Επιλέξτε φάκελο για μεταφόρτωση</translation>
<translation id="3660179305079774227">Πάνω βέλος</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Πριν από 1 δευτερόλεπτο}other{Πριν από # δευτερόλεπτα}}</translation>
<translation id="654149438358937226">Αποκλεισμός όλων των ειδοποιήσεων</translation>
<translation id="6567071839949112727">γονικό κλικ</translation>
+<translation id="6578407462441924264">Χωρίς όνομα</translation>
<translation id="6612467943526193239">Για να εξέλθετε από τη βαθμονόμηση, πατήστε Esc.</translation>
<translation id="6620110761915583480">Αποθήκευση Αρχείου</translation>
<translation id="6699343763173986273">Επόμενο κομμάτι πολυμέσων</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Πριν από 1 ώρα}other{Πριν από # ώρες}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Απομένει 1 δευτερόλεπτο}other{Απομένουν # δευτερόλεπτα}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, αυτόματη συμπλήρωση</translation>
<translation id="815598010540052116">Κύλιση κάτω</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Επόμενη σελίδα</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">ενεργοποίηση</translation>
<translation id="8393700583063109961">Αποστολή μηνύματος</translation>
<translation id="8394908167088220973">Αναπαραγωγή/παύση πολυμέσων</translation>
+<translation id="8420205633584771378">Να καταργηθεί αυτή η πρόταση;</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1έτ.}other{#έτ.}}</translation>
<translation id="8602707065186045623">Αρχείο <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Κουμπί "Πίσω"</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">ανοίγω</translation>
-<translation id="9038489124413477075">Φάκελος χωρίς όνομα</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 δευτ.}other{# δευτ.}}</translation>
<translation id="9059834730836941392">Σύμπτυξη ειδοποίησης</translation>
<translation id="9150735707954472829">Καρτέλα</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_en-GB.xtb b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
index 477460d7580..4b40154425f 100644
--- a/chromium/ui/strings/translations/ui_strings_en-GB.xtb
+++ b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 day ago}other{# days ago}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 minute ago}other{# minutes ago}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 m}other{# m}}</translation>
+<translation id="1181037720776840403">Remove</translation>
<translation id="1243314992276662751">Upload</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Down Arrow</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 day}other{# days}}</translation>
<translation id="335581015389089642">Speech</translation>
+<translation id="3462241349431650993">Hiding this suggestion will not show it again from your account across all your devices.</translation>
<translation id="3479552764303398839">Not now</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 day left}other{# days left}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Look Up “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Select Folder to Upload</translation>
<translation id="3660179305079774227">Up Arrow</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 second ago}other{# seconds ago}}</translation>
<translation id="654149438358937226">Block all notifications</translation>
<translation id="6567071839949112727">click ancestor</translation>
+<translation id="6578407462441924264">Unnamed</translation>
<translation id="6612467943526193239">To exit calibration press Esc.</translation>
<translation id="6620110761915583480">Save File</translation>
<translation id="6699343763173986273">Media Next Track</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 hour ago}other{# hours ago}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sec left}other{# secs left}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, autocomplete</translation>
<translation id="815598010540052116">Scroll Down</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">tick</translation>
<translation id="8393700583063109961">Send message</translation>
<translation id="8394908167088220973">Media Play/Pause</translation>
+<translation id="8420205633584771378">Remove this suggestion?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1y}other{#y}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> File (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Back button</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">open</translation>
-<translation id="9038489124413477075">Unnamed Folder</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 sec}other{# secs}}</translation>
<translation id="9059834730836941392">Collapse notification</translation>
<translation id="9150735707954472829">Tab</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_es-419.xtb b/chromium/ui/strings/translations/ui_strings_es-419.xtb
index 17fbbc33bb8..7db62a1e758 100644
--- a/chromium/ui/strings/translations/ui_strings_es-419.xtb
+++ b/chromium/ui/strings/translations/ui_strings_es-419.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Hace 1 día.}other{Hace # días.}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Hace 1 minuto}other{Hace # minutos}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}other{# min}}</translation>
+<translation id="1181037720776840403">Quitar</translation>
<translation id="1243314992276662751">Cargar</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Si ocultas esta sugerencia, no se mostrará de nuevo en ninguno de los dispositivos en los que hayas accedido a tu cuenta.</translation>
<translation id="3479552764303398839">Ahora no</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Falta 1 día.}other{Faltan # días.}}</translation>
+<translation id="3608915363409716668">+ <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Buscar "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Seleccionar carpeta para cargar</translation>
<translation id="3660179305079774227">Flecha arriba</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Hace 1 segundo}other{Hace # segundos}}</translation>
<translation id="654149438358937226">Bloquear todas las notificaciones</translation>
<translation id="6567071839949112727">hacer clic en principal</translation>
+<translation id="6578407462441924264">Sin nombre</translation>
<translation id="6612467943526193239">Para salir de las opciones de calibración, presiona Esc.</translation>
<translation id="6620110761915583480">Guardar archivo</translation>
<translation id="6699343763173986273">Pista multimedia siguiente</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Hace 1 hora.}other{Hace # horas.}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Falta 1 s.}other{Faltan # s.}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />; autocompletar</translation>
<translation id="815598010540052116">Desplazar hacia abajo</translation>
<translation id="8179976553408161302">Intro</translation>
<translation id="8210608804940886430">Avanzar página</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">marcar</translation>
<translation id="8393700583063109961">Enviar mensaje</translation>
<translation id="8394908167088220973">Reproducir o pausar contenido multimedia</translation>
+<translation id="8420205633584771378">¿Quieres quitar esta sugerencia?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 a}other{# a}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> Archivo (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Botón Atrás</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">abrir</translation>
-<translation id="9038489124413477075">Carpeta sin nombre</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}other{# s}}</translation>
<translation id="9059834730836941392">Contraer notificación</translation>
<translation id="9150735707954472829">Pestaña</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_es.xtb b/chromium/ui/strings/translations/ui_strings_es.xtb
index f814044cb0a..5dfc3a31ec7 100644
--- a/chromium/ui/strings/translations/ui_strings_es.xtb
+++ b/chromium/ui/strings/translations/ui_strings_es.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Hace 1 día}other{Hace # días}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Hace 1 minuto}other{Hace # minutos}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}other{# min}}</translation>
+<translation id="1181037720776840403">Quitar</translation>
<translation id="1243314992276662751">Subir</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Al ocultar esta sugerencia, no se volverá a mostrar para tu cuenta en ninguno de tus dispositivos.</translation>
<translation id="3479552764303398839">Ahora no</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Queda 1 día}other{Quedan # días}}</translation>
+<translation id="3608915363409716668">Más de <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Buscar <ph name="LOOKUP_STRING" /></translation>
<translation id="364720409959344976">Seleccionar una carpeta para subirla</translation>
<translation id="3660179305079774227">Flecha arriba</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Hace 1 segundo}other{Hace # segundos}}</translation>
<translation id="654149438358937226">Bloquear todas las notificaciones</translation>
<translation id="6567071839949112727">hacer clic en la superclase</translation>
+<translation id="6578407462441924264">Sin nombre</translation>
<translation id="6612467943526193239">Pulsa Esc para salir del modo de calibración.</translation>
<translation id="6620110761915583480">Guardar archivo</translation>
<translation id="6699343763173986273">Siguiente pista multimedia</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Hace 1 hora}other{Hace # horas}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Queda 1 s}other{Quedan # s}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, autocompletar</translation>
<translation id="815598010540052116">Desplazar hacia abajo</translation>
<translation id="8179976553408161302">Intro</translation>
<translation id="8210608804940886430">Avanzar página</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">marcar</translation>
<translation id="8393700583063109961">Enviar mensaje</translation>
<translation id="8394908167088220973">Pausar/Reproducir contenido multimedia</translation>
+<translation id="8420205633584771378">¿Quieres eliminar esta sugerencia?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 año}other{# años}}</translation>
<translation id="8602707065186045623">Archivo <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Botón Atrás</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">abrir</translation>
-<translation id="9038489124413477075">Carpeta sin nombre</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}other{# s}}</translation>
<translation id="9059834730836941392">Ocultar notificación</translation>
<translation id="9150735707954472829">Pestaña </translation>
diff --git a/chromium/ui/strings/translations/ui_strings_et.xtb b/chromium/ui/strings/translations/ui_strings_et.xtb
index 3b99834f71b..948481b6368 100644
--- a/chromium/ui/strings/translations/ui_strings_et.xtb
+++ b/chromium/ui/strings/translations/ui_strings_et.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 päev tagasi}other{# päeva tagasi}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 minut tagasi}other{# minutit tagasi}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1m}other{#m}}</translation>
+<translation id="1181037720776840403">Eemalda</translation>
<translation id="1243314992276662751">Laadi üles</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Kui selle soovituse peidate, ei kuvata seda enam teie kontol üheski teie seadmes.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Otsi terminit „<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Kausta valimine üleslaadimiseks</translation>
<translation id="3660179305079774227">Ülesnool</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 sekund tagasi}other{# sekundit tagasi}}</translation>
<translation id="654149438358937226">Blokeeri kõik märguanded</translation>
<translation id="6567071839949112727">kliki eellane</translation>
+<translation id="6578407462441924264">Nimetu</translation>
<translation id="6612467943526193239">Kalibreerimisest väljumiseks vajutage paoklahvi Esc.</translation>
<translation id="6620110761915583480">Faili salvestamine</translation>
<translation id="6699343763173986273">Meediumi järgmine lugu</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 tund tagasi}other{# tundi tagasi}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 s on jäänud}other{# s on jäänud}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automaatne täitmine</translation>
<translation id="815598010540052116">Keri alla</translation>
<translation id="8179976553408161302">Sisestusklahv</translation>
<translation id="8210608804940886430">Lehekülje lõppu</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">mrgista</translation>
<translation id="8393700583063109961">Saatke sõnum</translation>
<translation id="8394908167088220973">Meediumi esitamine/peatamine</translation>
+<translation id="8420205633584771378">Kas eemaldada see soovitus?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1a}other{#a}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> Fail (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Nupp Tagasi</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<translation id="9002566407876343676">avage</translation>
-<translation id="9038489124413477075">Nimeta kaust</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}other{# s}}</translation>
<translation id="9059834730836941392">Ahenda märguannet</translation>
<translation id="9150735707954472829">Vahekaart</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fa.xtb b/chromium/ui/strings/translations/ui_strings_fa.xtb
index e0cd88867c8..1e50dbf60ea 100644
--- a/chromium/ui/strings/translations/ui_strings_fa.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fa.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{۱ روز قبل}one{# روز قبل}other{# روز قبل}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{۱ دقیقه قبل}one{# دقیقه قبل}other{# دقیقه قبل}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{۱ دقیقه}one{# دقیقه}other{# دقیقه}}</translation>
+<translation id="1181037720776840403">حذف</translation>
<translation id="1243314992276662751">بارگذاری</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">پیکان پایین</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{۱ روز}one{# روز}other{# روز}}</translation>
<translation id="335581015389089642">صدا</translation>
+<translation id="3462241349431650993">اگر این پیشنهاد پنهان شود، در هیچ‌کدام از دستگاه‌هایتان دوباره از حسابتان نشان داده نمی‌شود.</translation>
<translation id="3479552764303398839">اکنون نه</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{۱ روز باقی مانده است}one{# روز باقی مانده است}other{# روز باقی مانده است}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" /> یا بیشتر</translation>
<translation id="3618849550573277856">جستجوی «<ph name="LOOKUP_STRING" />»</translation>
<translation id="364720409959344976">انتخاب پوشه برای بارگذاری</translation>
<translation id="3660179305079774227">پیکان بالا</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{۱ ثانیه قبل}one{# ثانیه قبل}other{# ثانیه قبل}}</translation>
<translation id="654149438358937226">مسدود کردن همه اعلان‌ها</translation>
<translation id="6567071839949112727">کلیک کردن روی نسخه اولیه</translation>
+<translation id="6578407462441924264">بدون نام</translation>
<translation id="6612467943526193239">‏برای خروج از کالیبراسیون، کلید Esc را فشار دهید.</translation>
<translation id="6620110761915583480">ذخیره کردن فایل</translation>
<translation id="6699343763173986273">آهنگ بعدی رسانه</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{۱ ساعت قبل}one{# ساعت قبل}other{# ساعت قبل}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{۱ ثانیه باقی مانده است}one{# ثانیه باقی مانده است}other{# ثانیه باقی مانده است}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />، تکمیل خودکار</translation>
<translation id="815598010540052116">پیمایش به پایین</translation>
<translation id="8179976553408161302">ورود</translation>
<translation id="8210608804940886430">صفحه پایین</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">علامت‌گذاری</translation>
<translation id="8393700583063109961">ارسال پیام</translation>
<translation id="8394908167088220973">پخش/مکث رسانه</translation>
+<translation id="8420205633584771378">این پیشنهاد حذف شود؟</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{۱ سال}one{# سال}other{# سال}}</translation>
<translation id="8602707065186045623">فایل <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> کیلوبایت/ثانیه</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">دکمه برگشت</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> کیلوبایت</translation>
<translation id="9002566407876343676">باز کنید</translation>
-<translation id="9038489124413477075">پوشه بدون نام</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{۱ ثانیه}one{# ثانیه}other{# ثانیه}}</translation>
<translation id="9059834730836941392">کوچک کردن اعلان</translation>
<translation id="9150735707954472829">Tab</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fi.xtb b/chromium/ui/strings/translations/ui_strings_fi.xtb
index c328e1808d5..e42dd7238df 100644
--- a/chromium/ui/strings/translations/ui_strings_fi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fi.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 päivä sitten}other{# päivää sitten}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 minuutti sitten}other{# minuuttia sitten}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}other{# min}}</translation>
+<translation id="1181037720776840403">Poista</translation>
<translation id="1243314992276662751">Lähetä</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Tämän ehdotuksen piilottaminen poistaa sen pysyvästi näkyvistä tililtäsi kaikilla laitteillasi.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Hae ”<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Valitse lähetettävä kansio</translation>
<translation id="3660179305079774227">Nuoli yl.</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 sekunti sitten}other{# sekuntia sitten}}</translation>
<translation id="654149438358937226">Estä kaikki ilmoitukset</translation>
<translation id="6567071839949112727">klikkaa edeltäjää</translation>
+<translation id="6578407462441924264">Nimetön</translation>
<translation id="6612467943526193239">Poistu kalibroinnista painamalla Esc.</translation>
<translation id="6620110761915583480">Tallenna tiedosto</translation>
<translation id="6699343763173986273">Media: seuraava kappale</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 tunti sitten}other{# tuntia sitten}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 s jäljellä}other{# s jäljellä}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automaattinen täydennys</translation>
<translation id="815598010540052116">Vieritä alas</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Sivu alas</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">valitse</translation>
<translation id="8393700583063109961">Lähetä viesti</translation>
<translation id="8394908167088220973">Media: toista/keskeytä</translation>
+<translation id="8420205633584771378">Poistetaanko tämä ehdotus?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 v}other{# v}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" />-tiedosto (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kt/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Takaisin-painike</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kt</translation>
<translation id="9002566407876343676">avata</translation>
-<translation id="9038489124413477075">Nimetön kansio</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}other{# s}}</translation>
<translation id="9059834730836941392">Tiivistä ilmoitus</translation>
<translation id="9150735707954472829">Välilehti</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fil.xtb b/chromium/ui/strings/translations/ui_strings_fil.xtb
index 21aa704068f..de8a3b97814 100644
--- a/chromium/ui/strings/translations/ui_strings_fil.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fil.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 araw ang nakalipas}one{# araw ang nakalipas}other{# na araw ang nakalipas}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 minuto ang nakalipas}one{# minuto ang nakalipas}other{# na minuto ang nakalipas}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 minuto}one{# minuto}other{# na minuto}}</translation>
+<translation id="1181037720776840403">Alisin</translation>
<translation id="1243314992276662751">I-upload</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Kapag itinago ang suhestyong ito, hindi ito muling ipapakita mula sa iyong account sa lahat ng device mo.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Hanapin ang “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Pumili ng Folder na I-a-upload</translation>
<translation id="3660179305079774227">Up Arrow</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 segundo ang nakalipas}one{# segundo ang nakalipas}other{# na segundo ang nakalipas}}</translation>
<translation id="654149438358937226">I-block ang lahat ng notification</translation>
<translation id="6567071839949112727">i-click ang ancestor</translation>
+<translation id="6578407462441924264">Walang Pangalan</translation>
<translation id="6612467943526193239">Upang lumabas sa pag-calibrate pindutin ang Esc.</translation>
<translation id="6620110761915583480">I-save ang File</translation>
<translation id="6699343763173986273">Susunod na Track ng Media</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 oras ang nakalipas}one{# oras ang nakalipas}other{# na oras ang nakalipas}}</translation>
<translation id="8131263257437993507">{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="8152264887680882389"><ph name="TEXT" />, Autocomplete</translation>
<translation id="815598010540052116">Mag-scroll Pababa</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">I-tsek</translation>
<translation id="8393700583063109961">Ipadala ang mensahe</translation>
<translation id="8394908167088220973">I-Play/I-Pause ang Media</translation>
+<translation id="8420205633584771378">Alisin ang suhestyong ito?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 taon}one{# taon}other{# na taon}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> File (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Button na Bumalik</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">buksan</translation>
-<translation id="9038489124413477075">Walang Pangalan na Folder</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 segundo}one{# segundo}other{# na segundo}}</translation>
<translation id="9059834730836941392">I-collapse ang notification</translation>
<translation id="9150735707954472829">Tab</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fr.xtb b/chromium/ui/strings/translations/ui_strings_fr.xtb
index 07e461c0569..13585c6ba8a 100644
--- a/chromium/ui/strings/translations/ui_strings_fr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fr.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Il y a 1 jour}one{Il y a # jour}other{Il y a # jours}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Il y a une minute}one{Il y a # minute}other{Il y a # minutes}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 m}one{# m}other{# m}}</translation>
+<translation id="1181037720776840403">Supprimer</translation>
<translation id="1243314992276662751">Importer</translation>
<translation id="1269641567813814718">Windows</translation>
<translation id="1293699935367580298">Échap</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Si vous choisissez de masquer cette suggestion, elle n'apparaîtra plus lorsque vous serez connecté à votre compte, sur tous vos appareils.</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="3608915363409716668">+ de <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Rechercher "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Sélectionner le dossier d'importation</translation>
<translation id="3660179305079774227">Haut</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Il y a une seconde}one{Il y a # seconde}other{Il y a # secondes}}</translation>
<translation id="654149438358937226">Bloquer toutes les notifications</translation>
<translation id="6567071839949112727">cliquer sur l'ancêtre</translation>
+<translation id="6578407462441924264">Sans nom</translation>
<translation id="6612467943526193239">Pour quitter le mode Étalonnage, appuyez sur Échap.</translation>
<translation id="6620110761915583480">Enregistrer le fichier</translation>
<translation id="6699343763173986273">Contenu multimédia : titre suivant</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Il y a 1 heure}one{Il y a # heure}other{Il y a # heures}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 s restante}one{# s restante}other{# s restantes}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, saisie semi-automatique</translation>
<translation id="815598010540052116">Défilement vers le bas</translation>
<translation id="8179976553408161302">Entrée</translation>
<translation id="8210608804940886430">Page suivante</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">cocher</translation>
<translation id="8393700583063109961">Envoyer un message</translation>
<translation id="8394908167088220973">Contenu multimédia : lecture/pause</translation>
+<translation id="8420205633584771378">Supprimer cette suggestion ?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 a}one{# a}other{# a}}</translation>
<translation id="8602707065186045623">Fichier <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> Ko/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Bouton Retour</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> Ko</translation>
<translation id="9002566407876343676">ouvrir</translation>
-<translation id="9038489124413477075">Dossier sans nom</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}one{# s}other{# s}}</translation>
<translation id="9059834730836941392">Réduire la notification</translation>
<translation id="9150735707954472829">Onglet</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_gu.xtb b/chromium/ui/strings/translations/ui_strings_gu.xtb
index 18b45cf4ebd..a7e55f392f9 100644
--- a/chromium/ui/strings/translations/ui_strings_gu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_gu.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 દિવસ પહેલા}one{# દિવસ પહેલાં}other{# દિવસ પહેલાં}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 મિનિટ પહેલાં}one{# મિનિટ પહેલાં}other{# મિનિટ પહેલાં}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 મિ}one{# મિ}other{# મિ}}</translation>
+<translation id="1181037720776840403">કાઢી નાખો</translation>
<translation id="1243314992276662751">અપલોડ કરો</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">નીચલો એરો</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 દિવસ}one{# દિવસ}other{# દિવસ}}</translation>
<translation id="335581015389089642">ભાષા</translation>
+<translation id="3462241349431650993">આ સૂચનને છુપાવવાથી તે તમારા એકાઉન્ટ પરથી તમારા સમગ્ર ડિવાઇસ પર ફરી બતાવવામાં આવશે નહીં.</translation>
<translation id="3479552764303398839">હમણાં નહીં</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 દિવસ બાકી}one{# દિવસ બાકી}other{# દિવસ બાકી}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” શોધો</translation>
<translation id="364720409959344976">અપલોડ કરવા માટે ફોલ્ડર પસંદ કરો</translation>
<translation id="3660179305079774227">ઉપર એરો</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 સેકંડ પહેલાં}one{# સેકંડ પહેલાં}other{# સેકંડ પહેલાં}}</translation>
<translation id="654149438358937226">તમામ નોટિફિકેશનને બ્લૉક કરો</translation>
<translation id="6567071839949112727">ઍન્સેસ્ટર પર ક્લિક કરો</translation>
+<translation id="6578407462441924264">અનામાંકિત</translation>
<translation id="6612467943526193239">કેલિબ્રેશનથી બહાર નીકળવા માટે Esc દબાવો.</translation>
<translation id="6620110761915583480">ફાઇલ સાચવો</translation>
<translation id="6699343763173986273">મીડિયા આગલો ટ્રૅક</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 કલાક પહેલા}one{# કલાક પહેલાં}other{# કલાક પહેલાં}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 સે બાકી}one{# સે બાકી}other{# સે બાકી}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, ઑટોમેટિક રીતે પૂર્ણ</translation>
<translation id="815598010540052116">નીચે સ્ક્રોલ કરો</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">પૃષ્ઠ નીચે</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">તપાસો</translation>
<translation id="8393700583063109961">સંદેશ મોકલો</translation>
<translation id="8394908167088220973">મીડિયા ચલાવો/થોભાવો</translation>
+<translation id="8420205633584771378">આ સૂચન કાઢી નાખીએ?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 વ}one{# વ}other{# વ}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> ફાઇલ (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">પાછળ બટન</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">ખોલો</translation>
-<translation id="9038489124413477075">અનામાંકિત ફોલ્ડર</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 સે}one{# સે}other{# સે}}</translation>
<translation id="9059834730836941392">નોટિફિકેશન સંકુચિત કરો</translation>
<translation id="9150735707954472829">ટૅબ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hi.xtb b/chromium/ui/strings/translations/ui_strings_hi.xtb
index b809c445c23..b745c82c050 100644
--- a/chromium/ui/strings/translations/ui_strings_hi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hi.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 दिन पहले}one{# दिन पहले}other{# दिन पहले}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 मिनट पहले}one{# मिनट पहले}other{# मिनट पहले}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 मिनट}one{# मिनट}other{# मिनट}}</translation>
+<translation id="1181037720776840403">हटाएं</translation>
<translation id="1243314992276662751">अपलोड करें</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">नीचे तीर</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 दिन}one{# दिन}other{# दिन}}</translation>
<translation id="335581015389089642">बोली</translation>
+<translation id="3462241349431650993">इस सुझाव को छुपाने से यह आपके सभी डिवाइस पर आपके खाते में फिर से दिखाई नहीं देगा.</translation>
<translation id="3479552764303398839">अभी नहीं</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 दिन शेष}one{# दिन शेष}other{# दिन शेष}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” को खोजें</translation>
<translation id="364720409959344976">अपलोड करने के लिए फ़ोल्‍डर चुनें</translation>
<translation id="3660179305079774227">ऊपर तीर</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 सेकंड पहले}one{# सेकंड पहले}other{# सेकंड पहले}}</translation>
<translation id="654149438358937226">सभी सूचनाएं ब्लॉक करें</translation>
<translation id="6567071839949112727">पहले वाले पर क्लिक करें</translation>
+<translation id="6578407462441924264">कोई नाम नहीं</translation>
<translation id="6612467943526193239">कैलिब्रेशन से बाहर निकलने के लिए Esc दबाएं.</translation>
<translation id="6620110761915583480">फ़ाइल सहेजें</translation>
<translation id="6699343763173986273">मीडिया अगला ट्रैक</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 घंटा पहले}one{# घंटे पहले}other{# घंटे पहले}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 सेकंड शेष}one{# सेकंड शेष}other{# सेकंड शेष}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, अपने आप पूरा</translation>
<translation id="815598010540052116">नीचे स्क्रोल करें</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">चेक करें</translation>
<translation id="8393700583063109961">संदेश भेजें</translation>
<translation id="8394908167088220973">मीडिया चलाएं/रोकें</translation>
+<translation id="8420205633584771378">यह सुझाव हटा दें?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1y}one{#y}other{#y}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> फ़ाइल (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> केबी/सेकंड</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">वापस जाएं बटन</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> केबी</translation>
<translation id="9002566407876343676">खोलें</translation>
-<translation id="9038489124413477075">अनाम फ़ोल्डर</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 सेकंड}one{# सेकंड}other{# सेकंड}}</translation>
<translation id="9059834730836941392">सूचना को छोटा करें</translation>
<translation id="9150735707954472829">टैब</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hr.xtb b/chromium/ui/strings/translations/ui_strings_hr.xtb
index 6811f587e9a..2446fe1b4a0 100644
--- a/chromium/ui/strings/translations/ui_strings_hr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hr.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Prije 1 dan}one{Prije # dan}few{Prije # dana}other{Prije # dana}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Prije 1 minute}one{prije # minute}few{prije # minute}other{prije # minuta}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}one{# min}few{# min}other{# min}}</translation>
+<translation id="1181037720776840403">Ukloni</translation>
<translation id="1243314992276662751">Prenesi</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Ako sakrijete prijedlog, on se neće više prikazivati iz vaših računa na svim vašim uređajima.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Potraži "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Odabir mape za prijenos</translation>
<translation id="3660179305079774227">Strelica prema gore</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Prije 1 sekunde}one{Prije # sekunde}few{Prije # sekunde}other{Prije # sekundi}}</translation>
<translation id="654149438358937226">Blokiraj sve obavijesti</translation>
<translation id="6567071839949112727">klikni nadređeni element</translation>
+<translation id="6578407462441924264">Bez naziva</translation>
<translation id="6612467943526193239">Za izlaz iz kalibracije pritisnite Esc.</translation>
<translation id="6620110761915583480">Spremi datoteku</translation>
<translation id="6699343763173986273">Sljedeći zapis Medija</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Prije 1 sat}one{Prije # sat}few{Prije # sata}other{Prije # sati}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Još 1 s}one{Još # s}few{Još # s}other{Još # s}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, samodovrši</translation>
<translation id="815598010540052116">Pomakni se dolje</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Stranica prema dolje</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">označi</translation>
<translation id="8393700583063109961">Pošaljite poruku</translation>
<translation id="8394908167088220973">Reproduciraj/pauziraj Medije</translation>
+<translation id="8420205633584771378">Ukloniti prijedlog?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 g}one{# g}few{# g}other{# g}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> Datoteka (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Gumb Natrag</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">otvaranje</translation>
-<translation id="9038489124413477075">Neimenovana mapa</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}one{# s}few{# s}other{# s}}</translation>
<translation id="9059834730836941392">Sažmi obavijest</translation>
<translation id="9150735707954472829">Kartica</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hu.xtb b/chromium/ui/strings/translations/ui_strings_hu.xtb
index 41c0a7b397f..75a90dc86c0 100644
--- a/chromium/ui/strings/translations/ui_strings_hu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hu.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 napja}other{# napja}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 perce}other{# perce}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 p}other{# p}}</translation>
+<translation id="1181037720776840403">Eltávolítás</translation>
<translation id="1243314992276662751">Feltöltés</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Ha elrejti a javaslatot, a továbbiakban nem jelenik meg a fiókjával használt egyik eszközön sem.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</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>
<translation id="3660179305079774227">Felfelé nyíl</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 másodperce}other{# másodperce}}</translation>
<translation id="654149438358937226">Minden értesítés letiltása</translation>
<translation id="6567071839949112727">kattintás az elődre</translation>
+<translation id="6578407462441924264">Név nélküli</translation>
<translation id="6612467943526193239">Ha ki szeretne lépni a kalibrálásból, nyomja meg az Esc billentyűt.</translation>
<translation id="6620110761915583480">Fájl mentése</translation>
<translation id="6699343763173986273">Következő szám</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 órája}other{# órája}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 mp van hátra}other{# mp van hátra}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automatikus kiegészítés</translation>
<translation id="815598010540052116">Görgetés lefelé</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">Megjelölés</translation>
<translation id="8393700583063109961">Üzenet küldése</translation>
<translation id="8394908167088220973">Lejátszás/szüneteltetés</translation>
+<translation id="8420205633584771378">Eltávolítja ezt a javaslatot?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 é}other{# é}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> fájl (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Vissza gomb</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<translation id="9002566407876343676">megnyitás</translation>
-<translation id="9038489124413477075">Név nélküli mappa</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 mp}other{# mp}}</translation>
<translation id="9059834730836941392">Értesítés összecsukása</translation>
<translation id="9150735707954472829">Lap</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_id.xtb b/chromium/ui/strings/translations/ui_strings_id.xtb
index 8a35010329b..a9fe1144f5f 100644
--- a/chromium/ui/strings/translations/ui_strings_id.xtb
+++ b/chromium/ui/strings/translations/ui_strings_id.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 hari yang lalu}other{# hari yang lalu}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 menit yang lalu}other{# menit yang lalu}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 m}other{# m}}</translation>
+<translation id="1181037720776840403">Hapus</translation>
<translation id="1243314992276662751">Upload</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Panah Bawah</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 hari}other{# hari}}</translation>
<translation id="335581015389089642">Ucapan</translation>
+<translation id="3462241349431650993">Jika disembunyikan, saran ini tidak akan ditampilkan lagi dari akun Anda di semua perangkat.</translation>
<translation id="3479552764303398839">Jangan sekarang</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 hari lagi}other{# hari lagi}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Cari "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Pilih Folder untuk Diunggah</translation>
<translation id="3660179305079774227">Panah Atas</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 detik yang lalu}other{# detik yang lalu}}</translation>
<translation id="654149438358937226">Blokir semua notifikasi</translation>
<translation id="6567071839949112727">klik ancestor</translation>
+<translation id="6578407462441924264">Tanpa Nama</translation>
<translation id="6612467943526193239">Untuk keluar dari kalibrasi, tekan Esc.</translation>
<translation id="6620110761915583480">Simpan File</translation>
<translation id="6699343763173986273">Lacak Media Berikutnya</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 jam yang lalu}other{# jam yang lalu}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 dtk lagi}other{# dtk lagi}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, Dilengkapi otomatis</translation>
<translation id="815598010540052116">Gulir ke Bawah</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">centangi</translation>
<translation id="8393700583063109961">Kirim pesan</translation>
<translation id="8394908167088220973">Putar/Jeda Media</translation>
+<translation id="8420205633584771378">Hapus saran ini?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1t}other{#t}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> File (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/dtk</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Tombol kembali</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">buka</translation>
-<translation id="9038489124413477075">Folder Tanpa Nama</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 dtk}other{# dtk}}</translation>
<translation id="9059834730836941392">Ciutkan notifikasi</translation>
<translation id="9150735707954472829">Tab</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_it.xtb b/chromium/ui/strings/translations/ui_strings_it.xtb
index 89c47a9870f..9d662111bcd 100644
--- a/chromium/ui/strings/translations/ui_strings_it.xtb
+++ b/chromium/ui/strings/translations/ui_strings_it.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 giorno fa}other{# giorni fa}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 minuto fa}other{# minuti fa}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 m}other{# m}}</translation>
+<translation id="1181037720776840403">Rimuovi</translation>
<translation id="1243314992276662751">Carica</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Freccia GIÙ</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 giorno}other{# giorni}}</translation>
<translation id="335581015389089642">Voce</translation>
+<translation id="3462241349431650993">Questo suggerimento, se nascosto, non verrà più mostrato dal tuo account su tutti i tuoi dispositivi.</translation>
<translation id="3479552764303398839">Non adesso</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 giorno rimanente}other{# giorni rimanenti}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Cerca "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Seleziona la cartella da caricare</translation>
<translation id="3660179305079774227">Freccia SU</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 secondo fa}other{# secondi fa}}</translation>
<translation id="654149438358937226">Blocca tutte le notifiche</translation>
<translation id="6567071839949112727">fai clic su predecessore</translation>
+<translation id="6578407462441924264">Senza nome</translation>
<translation id="6612467943526193239">Per uscire dalla calibrazione premi Esc.</translation>
<translation id="6620110761915583480">Salva file</translation>
<translation id="6699343763173986273">Traccia successiva contenuti multimediali</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 ora fa}other{# ore fa}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sec rimanente}other{# sec rimanenti}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, completamento automatico</translation>
<translation id="815598010540052116">Scorri verso il basso</translation>
<translation id="8179976553408161302">Invio</translation>
<translation id="8210608804940886430">Pagina giù</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">seleziona</translation>
<translation id="8393700583063109961">Invia messaggio</translation>
<translation id="8394908167088220973">Play/Pausa contenuti multimediali</translation>
+<translation id="8420205633584771378">Rimuovere questo suggerimento?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 a}other{# a}}</translation>
<translation id="8602707065186045623">File <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Pulsante Indietro</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<translation id="9002566407876343676">apri</translation>
-<translation id="9038489124413477075">Cartella senza nome</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 sec}other{# sec}}</translation>
<translation id="9059834730836941392">Comprimi la notifica</translation>
<translation id="9150735707954472829">Scheda</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_iw.xtb b/chromium/ui/strings/translations/ui_strings_iw.xtb
index dc717890dde..1db0d804fb7 100644
--- a/chromium/ui/strings/translations/ui_strings_iw.xtb
+++ b/chromium/ui/strings/translations/ui_strings_iw.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{לפני יום אחד}two{לפני יומיים}many{לפני # ימים}other{לפני # ימים}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{לפני דקה אחת}two{לפני # דקות}many{לפני # דקות}other{לפני # דקות}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{דקה}two{# דק}many{# דק}other{# דק}}</translation>
+<translation id="1181037720776840403">הסרה</translation>
<translation id="1243314992276662751">העלה</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">חץ למטה</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{יום אחד}two{יומיים}many{# ימים}other{# ימים}}</translation>
<translation id="335581015389089642">דיבור</translation>
+<translation id="3462241349431650993">הסתרת ההצעה הזו תגרום לכך שלא תופיע שוב בחשבון בכל המכשירים שברשותך.</translation>
<translation id="3479552764303398839">לא עכשיו</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{נותר יום אחד}two{נותרו יומיים}many{נותרו # ימים}other{נותרו # ימים}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">חפש “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">בחירת תיקיה להעלאה</translation>
<translation id="3660179305079774227">חץ למעלה</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{לפני שנייה אחת}two{לפני # שניות}many{לפני # שניות}other{לפני # שניות}}</translation>
<translation id="654149438358937226">חסימת כל ההודעות</translation>
<translation id="6567071839949112727">לחיצה על אב</translation>
+<translation id="6578407462441924264">ללא שם</translation>
<translation id="6612467943526193239">‏הקש על Esc כדי לצאת מהכיול.</translation>
<translation id="6620110761915583480">שמור קובץ</translation>
<translation id="6699343763173986273">הרצועה הבאה במדיה</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{לפני שעה אחת}two{לפני שעתיים}many{לפני # שעות}other{לפני # שעות}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{נותרה שנ‘ אחת}two{נותרו # שנ‘}many{נותרו # שנ‘}other{נותרו # שנ‘}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, השלמה אוטומטית</translation>
<translation id="815598010540052116">גלול למטה</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">דף למטה</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">סמן</translation>
<translation id="8393700583063109961">שלח הודעה</translation>
<translation id="8394908167088220973">הפעלה/השהיה של המדיה</translation>
+<translation id="8420205633584771378">להסיר את ההצעה הזו?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{שנה}two{# שנ}many{# שנ}other{# שנ}}</translation>
<translation id="8602707065186045623">קובץ <ph name="SAVEAS_EXTENSION_TYPE" /> (<ph name="SAVEAS_EXTENSION_NAME" />.)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s‎</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">לחצן 'הקודם'</translation>
<translation id="8901569739625249689">‏<ph name="QUANTITY" /> KB‏</translation>
<translation id="9002566407876343676">פתח</translation>
-<translation id="9038489124413477075">תיקייה ללא שם</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{שנ‘ אחת}two{# שנ‘}many{# שנ‘}other{# שנ‘}}</translation>
<translation id="9059834730836941392">כיווץ ההודעה</translation>
<translation id="9150735707954472829">כרטיסייה</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ja.xtb b/chromium/ui/strings/translations/ui_strings_ja.xtb
index 51e5001a3a3..3f7f4a72dec 100644
--- a/chromium/ui/strings/translations/ui_strings_ja.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ja.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 日前}other{# 日前}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 分前}other{# 分前}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1分}other{#分}}</translation>
+<translation id="1181037720776840403">削除</translation>
<translation id="1243314992276662751">アップロード</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">下矢印キー</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 日}other{# 日}}</translation>
<translation id="335581015389089642">スピーチ</translation>
+<translation id="3462241349431650993">この候補を非表示にすると、お使いのすべてのデバイスでアカウントに表示されなくなります。</translation>
<translation id="3479552764303398839">後で</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{残り 1 日}other{残り # 日}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />~</translation>
<translation id="3618849550573277856">「<ph name="LOOKUP_STRING" />」を検索</translation>
<translation id="364720409959344976">アップロードするフォルダを選択</translation>
<translation id="3660179305079774227">上矢印キー</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation>
<translation id="654149438358937226">通知をすべてブロックする</translation>
<translation id="6567071839949112727">上位要素をクリック</translation>
+<translation id="6578407462441924264">名前なし</translation>
<translation id="6612467943526193239">キャリブレーションを終了するには Esc キーを押します。</translation>
<translation id="6620110761915583480">ファイルを保存</translation>
<translation id="6699343763173986273">メディアの次のトラック</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 時間前}other{# 時間前}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{残り 1 秒}other{残り # 秒}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />、オートコンプリート</translation>
<translation id="815598010540052116">下にスクロール</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">次のページへ</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">チェックを付ける</translation>
<translation id="8393700583063109961">メッセージを送信</translation>
<translation id="8394908167088220973">メディアの再生/一時停止</translation>
+<translation id="8420205633584771378">この候補を削除しますか?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1年}other{#年}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> ファイル (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/秒</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">戻るボタン</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">開く</translation>
-<translation id="9038489124413477075">名前のないフォルダ</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 秒}other{# 秒}}</translation>
<translation id="9059834730836941392">通知を折りたたむ</translation>
<translation id="9150735707954472829">タブ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_kn.xtb b/chromium/ui/strings/translations/ui_strings_kn.xtb
index da61a1730c8..59075009150 100644
--- a/chromium/ui/strings/translations/ui_strings_kn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_kn.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 ದಿನದ ಹಿಂದೆ}one{# ದಿನಗಳ ಹಿಂದೆ}other{# ದಿನಗಳ ಹಿಂದೆ}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 ನಿಮಿಷದ ಹಿಂದೆ}one{# ನಿಮಿಷಗಳ ಹಿಂದೆ}other{# ನಿಮಿಷಗಳ ಹಿಂದೆ}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1ಮೀ}one{#ಮೀ}other{#ಮೀ}}</translation>
+<translation id="1181037720776840403">ತೆಗೆದುಹಾಕಿ</translation>
<translation id="1243314992276662751">ಅಪ್‌ಲೋಡ್</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">ಕೆಳಗಿನ ಬಾಣದ ಗುರುತು</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ದಿನ}one{# ದಿನಗಳು}other{# ದಿನಗಳು}}</translation>
<translation id="335581015389089642">ಧ್ವನಿ</translation>
+<translation id="3462241349431650993">ಈ ಸಲಹೆಯನ್ನು ಮರೆಮಾಡುವುದರಿಂದ, ನಿಮ್ಮ ಎಲ್ಲಾ ಸಾಧನಗಳಲ್ಲಿ ನಿಮ್ಮ ಖಾತೆಯಿಂದ ಇದನ್ನು ಮತ್ತೆ ತೋರಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
<translation id="3479552764303398839">ಈಗ ಬೇಡ</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ದಿನ ಬಾಕಿ ಉಳಿದಿದೆ}one{# ದಿನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}other{# ದಿನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” ನೋಡಿ</translation>
<translation id="364720409959344976">ಅಪ್‌ಲೋಡ್ ಮಾಡಲು ಫೋಲ್ಡರ್ ಆಯ್ಕೆಮಾಡಿ</translation>
<translation id="3660179305079774227">ಮೇಲಿನ ಬಾಣದ ಗುರುತು</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 ಸೆಕೆಂಡ್ ಹಿಂದೆ}one{# ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ}other{# ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ}}</translation>
<translation id="654149438358937226">ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ</translation>
<translation id="6567071839949112727">ಪೂರ್ವಜರನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ</translation>
+<translation id="6578407462441924264">ಹೆಸರಿಸದಿರುವುದು</translation>
<translation id="6612467943526193239">ಮಾಪನಾಂಕದಿಂದ ನಿರ್ಗಮಿಸಲು Esc ಒತ್ತಿರಿ.</translation>
<translation id="6620110761915583480">ಫೈಲ್ ಉಳಿಸು</translation>
<translation id="6699343763173986273">ಮೀಡಿಯಾದ ಮುಂದಿನ ಟ್ರ್ಯಾಕ್</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 ಗಂಟೆ ಹಿಂದೆ}one{# ಗಂಟೆಗಳ ಹಿಂದೆ}other{# ಗಂಟೆಗಳ ಹಿಂದೆ}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 ಸೆಕೆಂಡ್ ಬಾಕಿ ಉಳಿದಿದೆ}one{# ಸೆಕೆಂಡುಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}other{# ಸೆಕೆಂಡುಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, ಸ್ವಯಂಪೂರ್ಣಗೊಳಿಸುವಿಕೆ</translation>
<translation id="815598010540052116">ಕೆಳಗೆ ಸ್ಕ್ರೋಲ್ ಮಾಡು</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">ಪುಟ ಕೆಳಗೆ</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">ಪರಿಶೀಲಿಸಿ</translation>
<translation id="8393700583063109961">ಸಂದೇಶ ಕಳುಹಿಸು</translation>
<translation id="8394908167088220973">ಮೀಡಿಯಾ ಪ್ಲೇ/ವಿರಾಮ</translation>
+<translation id="8420205633584771378">ಈ ಸಲಹೆಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1ವ}one{#ವ}other{#ವ}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> ಫೈಲ್ (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s </translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">ಹಿಂದೆ ಬಟನ್</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">ತೆರೆ</translation>
-<translation id="9038489124413477075">ಹೆಸರಿಸದ ಫೋಲ್ಡರ್</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 ಸೆಕೆಂಡ್}one{# ಸೆಕೆಂಡುಗಳು}other{# ಸೆಕೆಂಡುಗಳು}}</translation>
<translation id="9059834730836941392">ಕುಗ್ಗಿಸುವ ಅಧಿಸೂಚನೆ</translation>
<translation id="9150735707954472829">ಟ್ಯಾಬ್</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ko.xtb b/chromium/ui/strings/translations/ui_strings_ko.xtb
index f2ac213bfb7..7c4a550356f 100644
--- a/chromium/ui/strings/translations/ui_strings_ko.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ko.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1일 전}other{#일 전}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1분 전}other{#분 전}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1분}other{#분}}</translation>
+<translation id="1181037720776840403">삭제</translation>
<translation id="1243314992276662751">업로드</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">아래 화살표</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1일}other{#일}}</translation>
<translation id="335581015389089642">음성</translation>
+<translation id="3462241349431650993">이 추천을 숨기면 모든 기기의 계정에서 이 추천이 다시 표시되지 않습니다.</translation>
<translation id="3479552764303398839">나중에</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1일 남음}other{#일 남음}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" /> 이상</translation>
<translation id="3618849550573277856">'<ph name="LOOKUP_STRING" />' 찾기</translation>
<translation id="364720409959344976">업로드할 폴더 선택</translation>
<translation id="3660179305079774227">위쪽 화살표</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1초 전}other{#초 전}}</translation>
<translation id="654149438358937226">모든 알림 차단</translation>
<translation id="6567071839949112727">상위 개체 클릭</translation>
+<translation id="6578407462441924264">이름 없음</translation>
<translation id="6612467943526193239">보정을 종료하려면 Esc를 누르세요.</translation>
<translation id="6620110761915583480">파일 저장</translation>
<translation id="6699343763173986273">미디어 다음 트랙</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1시간 전}other{#시간 전}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1초 남음}other{#초 남음}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, 자동 완성</translation>
<translation id="815598010540052116">아래로 스크롤</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">페이지 아래로</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">선택</translation>
<translation id="8393700583063109961">메시지 보내기</translation>
<translation id="8394908167088220973">미디어 재생/일시중지</translation>
+<translation id="8420205633584771378">추천을 삭제하시겠습니까?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1년}other{#년}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> 파일(.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" />KB/초</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">뒤로 버튼</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" />KB</translation>
<translation id="9002566407876343676">열기</translation>
-<translation id="9038489124413477075">이름이 없는 폴더</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1초}other{#초}}</translation>
<translation id="9059834730836941392">알림 접기</translation>
<translation id="9150735707954472829">탭</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lt.xtb b/chromium/ui/strings/translations/ui_strings_lt.xtb
index 4d160fd66d6..c4b1a94c63d 100644
--- a/chromium/ui/strings/translations/ui_strings_lt.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lt.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Prieš 1 dieną}one{Prieš # dieną}few{Prieš # dienas}many{Prieš # dienos}other{Prieš # dienų}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Prieš 1 minutę}one{Prieš # minutę}few{Prieš # minutes}many{Prieš # minutės}other{Prieš # minučių}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min.}one{# min.}few{# min.}many{# min.}other{# min.}}</translation>
+<translation id="1181037720776840403">Pašalinti</translation>
<translation id="1243314992276662751">Įkelti</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Paslėpus šį pasiūlymą jis nebebus rodomas jūsų paskyroje visuose įrenginiuose.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" /> ir daugiau</translation>
<translation id="3618849550573277856">Ieškoti „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Pasirinkite norimą įkelti aplanką</translation>
<translation id="3660179305079774227">Rodyklė „Aukštyn“</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Prieš 1 sekundę}one{Prieš # sekundę}few{Prieš # sekundes}many{Prieš # sekundės}other{Prieš # sekundžių}}</translation>
<translation id="654149438358937226">Blokuoti visus pranešimus</translation>
<translation id="6567071839949112727">spustelėti aukštesnio lygmens elementą</translation>
+<translation id="6578407462441924264">Be pavadinimo</translation>
<translation id="6612467943526193239">Jei norite išeiti iš kalibravimo, paspauskite „Esc“.</translation>
<translation id="6620110761915583480">Išsaugoti failą</translation>
<translation id="6699343763173986273">Kitas medijos takelis</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + „<ph name="KEY_COMBO_NAME" />“</translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Prieš 1 valandą}one{Prieš # valandą}few{Prieš # valandas}many{Prieš # valandos}other{Prieš # valandų}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Liko 1 sek.}one{Liko # sek.}few{Liko # sek.}many{Liko # sek.}other{Liko # sek.}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automatinis užbaigimas</translation>
<translation id="815598010540052116">Slinkti žemyn</translation>
<translation id="8179976553408161302">Įvesti</translation>
<translation id="8210608804940886430">Puslapį žemyn</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">tikrinti</translation>
<translation id="8393700583063109961">Siųsti pranešimą</translation>
<translation id="8394908167088220973">Leisti / pristabdyti mediją</translation>
+<translation id="8420205633584771378">Pašalinti šį siūlymą?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 m.}one{# m.}few{# m.}many{# m.}other{# m.}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> failas (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB per sek.</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Mygtukas „Atgal“</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">atidaryti</translation>
-<translation id="9038489124413477075">Aplankas be pavadinimo</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 sek.}one{# sek.}few{# sek.}many{# sek.}other{# sek.}}</translation>
<translation id="9059834730836941392">Sutraukti pranešimą</translation>
<translation id="9150735707954472829">Skirtukas</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lv.xtb b/chromium/ui/strings/translations/ui_strings_lv.xtb
index 00b029ccb5f..fc7745126cc 100644
--- a/chromium/ui/strings/translations/ui_strings_lv.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lv.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Pirms 1 dienas}zero{Pirms # dienām}one{Pirms # dienas}other{Pirms # dienām}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Pirms 1 minūtes}zero{Pirms # minūtēm}one{Pirms # minūtes}other{Pirms # minūtēm}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}zero{# min}one{# min}other{# min}}</translation>
+<translation id="1181037720776840403">Noņemt</translation>
<translation id="1243314992276662751">Augšupielādēt</translation>
<translation id="1269641567813814718">Windows</translation>
<translation id="1293699935367580298">Atsolis</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Ja noslēpsiet šo ieteikumu, tas vairs netiks rādīts jūsu kontā nevienā jūsu ierīcē.</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="3608915363409716668">Vairāk nekā <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Meklēt “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Augšupielādējamās mapes atlase</translation>
<translation id="3660179305079774227">Bulta augšup</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Pirms 1 sekundes}zero{Pirms # sekundēm}one{Pirms # sekundes}other{Pirms # sekundēm}}</translation>
<translation id="654149438358937226">Bloķēt visus paziņojumus</translation>
<translation id="6567071839949112727">noklikšķināt uz priekšteča</translation>
+<translation id="6578407462441924264">Bez nosaukuma</translation>
<translation id="6612467943526193239">Lai izietu no kalibrēšanas, nospiediet Esc.</translation>
<translation id="6620110761915583480">Saglabāt failu</translation>
<translation id="6699343763173986273">Multivide — nākamā dziesma</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Pirms 1 stundas}zero{Pirms # stundām}one{Pirms # stundas}other{Pirms # stundām}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Atlikusi 1 s}zero{Atlikušas # s}one{Atlikusi # s}other{Atlikušas # s}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automātiski pabeigts</translation>
<translation id="815598010540052116">Ritināt lejup</translation>
<translation id="8179976553408161302">Ievadīt</translation>
<translation id="8210608804940886430">Lejup</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">prbaudt</translation>
<translation id="8393700583063109961">Sūtīt ziņojumu</translation>
<translation id="8394908167088220973">Multivide — atskaņot/apturēt</translation>
+<translation id="8420205633584771378">Vai noņemt šo ieteikumu?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 g.}zero{# g.}one{# g.}other{# g.}}</translation>
<translation id="8602707065186045623">Fails <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Poga Atpakaļ</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">atvērt</translation>
-<translation id="9038489124413477075">Mape bez nosaukuma</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}zero{# s}one{# s}other{# s}}</translation>
<translation id="9059834730836941392">Sakļaut paziņojumu</translation>
<translation id="9150735707954472829">Cilne</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ml.xtb b/chromium/ui/strings/translations/ui_strings_ml.xtb
index 4ac3c5545e0..9c2c30d8a86 100644
--- a/chromium/ui/strings/translations/ui_strings_ml.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ml.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{ഒരു ദിവസം മുമ്പ്}other{# ദിവസം മുമ്പ്}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{ഒരു മിനിറ്റിന് മുമ്പ്}other{# മിനിറ്റ് മുമ്പ്}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{ 1 മീറ്റര്‍}other{# മീറ്റർ}}</translation>
+<translation id="1181037720776840403">നീക്കംചെയ്യൂ</translation>
<translation id="1243314992276662751">അപ്‌ലോഡുചെയ്യുക</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">താഴേക്കുള്ള ആരോ അടയാളം</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{ഒരു ദിവസം}other{# ദിവസം}}</translation>
<translation id="335581015389089642">സംഭാഷണം</translation>
+<translation id="3462241349431650993">ഈ നിർദ്ദേശം അദൃശ്യമാക്കിയാൽ അത് ഉപകരണങ്ങളിൽ ഉടനീളമുള്ള നിങ്ങളുടെ അക്കൗണ്ടിൽ കാണിക്കില്ല.</translation>
<translation id="3479552764303398839">ഇപ്പോഴല്ല</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{ഒരു ദിവസം ശേഷിക്കുന്നു}other{# ദിവസം ശേഷിക്കുന്നു}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” തിരയുക</translation>
<translation id="364720409959344976">അപ്‌ലോഡുചെയ്യുന്നതിന് ഫോൾഡർ തിരഞ്ഞെടുക്കുക</translation>
<translation id="3660179305079774227">മുകളിലേക്കുള്ള അമ്പടയാളം</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 സെക്കൻഡ് മുമ്പ്}other{# സെക്കൻഡ് മുമ്പ്}}</translation>
<translation id="654149438358937226">എല്ലാ അറിയിപ്പുകളും ബ്ലോക്ക് ചെയ്യുക</translation>
<translation id="6567071839949112727">ആൻസിസ്റ്ററിൽ ക്ലിക്ക് ചെയ്യുക</translation>
+<translation id="6578407462441924264">പേരില്ലാത്തത്</translation>
<translation id="6612467943526193239">കാലിബറേഷനിൽ നിന്ന് പുറത്തുകടക്കാൻ Esc അമർത്തുക.</translation>
<translation id="6620110761915583480">ഫയല്‍‌ സംരക്ഷിക്കുക</translation>
<translation id="6699343763173986273">അടുത്ത മീഡിയ ട്രാക്ക്</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{ഒരു മണിക്കൂര്‍ മുമ്പ്}other{# മണിക്കൂർ മുമ്പ്}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{ഒരു സെക്കൻഡ് ശേഷിക്കുന്നു}other{# സെക്കൻഡ് ശേഷിക്കുന്നു}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, സ്വയമേവ പൂർത്തിയാക്കുക</translation>
<translation id="815598010540052116">താഴേക്ക് സ്ക്രോള്‍ചെയ്യൂ</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">താഴെയുള്ള പേജുകള്‍</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">പരിശോധിക്കൂ</translation>
<translation id="8393700583063109961">സന്ദേശം അയയ്ക്കുക</translation>
<translation id="8394908167088220973">മീഡിയ പ്ലേ ചെയ്യുക/താൽക്കാലികമായി നിർത്തുക</translation>
+<translation id="8420205633584771378">ഈ നിർദ്ദേശം നീക്കം ചെയ്യണോ?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1വർഷം}other{#വർഷം}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> ഫയല്‍ (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">ബാക്ക് ബട്ടൺ</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">തുറക്കുക</translation>
-<translation id="9038489124413477075">പേരിടാത്ത ഫോൾഡർ</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{ഒരു സെക്കൻഡ്}other{# സെക്കൻഡ്}}</translation>
<translation id="9059834730836941392">അറിയിപ്പ് ചുരുക്കുക</translation>
<translation id="9150735707954472829">ടാബ്</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_mr.xtb b/chromium/ui/strings/translations/ui_strings_mr.xtb
index 690566e8790..0341a97f077 100644
--- a/chromium/ui/strings/translations/ui_strings_mr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_mr.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 दिवसापूर्वी}one{# दिवसापूर्वी}other{# दिवसांपूर्वी}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 मिनिटापूर्वी}one{# मिनिटापूर्वी}other{# मिनिटांपूर्वी}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1मि}one{#मि}other{#मि}}</translation>
+<translation id="1181037720776840403">काढून टाका</translation>
<translation id="1243314992276662751">अपलोड करा</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Down Arrow</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 दिवस}one{# दिवस}other{# दिवस}}</translation>
<translation id="335581015389089642">भाषण</translation>
+<translation id="3462241349431650993">ही सूचना लपवल्याने ती तुमच्या सर्व डिव्हाइसवर तुमच्या खात्यामधून पुन्हा दाखवली जाणार नाही.</translation>
<translation id="3479552764303398839">सध्या नाही</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 दिवस शिल्लक}one{# दिवस शिल्लक}other{# दिवस शिल्लक}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” पहा</translation>
<translation id="364720409959344976">अपलोड करण्यासाठी फोल्डर निवडा</translation>
<translation id="3660179305079774227">Up Arrow</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 सेकंदापूर्वी}one{# सेकंदापूर्वी}other{# सेकंदांपूर्वी}}</translation>
<translation id="654149438358937226">सर्व सूचना ब्लॉक करा</translation>
<translation id="6567071839949112727">पूर्वजवर क्लिक करा</translation>
+<translation id="6578407462441924264">नाव नसलेले</translation>
<translation id="6612467943526193239">कॅलिब्रेशनमधून बाहेर पडण्‍यासाठी Esc दाबा.</translation>
<translation id="6620110761915583480">फाइल सेव्ह करा</translation>
<translation id="6699343763173986273">मीडिया पुढील ट्रॅक</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 तासापूर्वी}one{# तासापूर्वी}other{# तासांपूर्वी}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 सेकंद शिल्लक}one{# सेकंद शिल्लक}other{# सेकंद शिल्लक}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, ऑटोकंप्लीट</translation>
<translation id="815598010540052116">खाली स्क्रोल करा</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">पृष्ठ खाली</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">तपासा</translation>
<translation id="8393700583063109961">संदेश पाठवा</translation>
<translation id="8394908167088220973">मीडिया प्ले करा/विराम द्या</translation>
+<translation id="8420205633584771378">ही सूचना काढून टाकायची आहे का?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1वर्ष}one{#वर्ष}other{#वर्षे}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> फाइल (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">मागे जा बटण</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">उघडा</translation>
-<translation id="9038489124413477075">अनामित फोल्डर</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 से}one{# से}other{# से}}</translation>
<translation id="9059834730836941392">सूचना संकुचित करा</translation>
<translation id="9150735707954472829">टॅब</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ms.xtb b/chromium/ui/strings/translations/ui_strings_ms.xtb
index 989667bf15b..52effb4dc87 100644
--- a/chromium/ui/strings/translations/ui_strings_ms.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ms.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 hari yang lalu}other{# hari yang lalu}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Seminit yang lalu}other{# minit yang lalu}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1m}other{#m}}</translation>
+<translation id="1181037720776840403">Alih keluar</translation>
<translation id="1243314992276662751">Muat naik</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Cadangan tidak akan dipaparkan lagi daripada akaun anda pada semua peranti jika cadangan disembunyikan.</translation>
<translation id="3479552764303398839">Bukan sekarang</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 hari lagi}other{# hari lagi}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Cari “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Pilih Folder untuk Dimuat Naik</translation>
<translation id="3660179305079774227">Anak Panah Atas</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Sesaat yang lalu}other{# saat yang lalu}}</translation>
<translation id="654149438358937226">Sekat semua pemberitahuan</translation>
<translation id="6567071839949112727">klik pewaris</translation>
+<translation id="6578407462441924264">Tidak bernama</translation>
<translation id="6612467943526193239">Untuk keluar daripada penentukuran, tekan Esc.</translation>
<translation id="6620110761915583480">Simpan Fail</translation>
<translation id="6699343763173986273">Lagu Media Seterusnya</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 jam yang lalu}other{# jam yang lalu}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 saat lagi}other{# saat lagi}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, Autolengkap</translation>
<translation id="815598010540052116">Tatal Ke Bawah</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Ke Bawah Halaman</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">periksa</translation>
<translation id="8393700583063109961">Hantar mesej</translation>
<translation id="8394908167088220973">Main/Jeda Media</translation>
+<translation id="8420205633584771378">Alih keluar cadangan ini?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1t}other{#t}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> Fail (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Butang kembali</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">buka</translation>
-<translation id="9038489124413477075">Folder Tanpa Nama</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 saat}other{# saat}}</translation>
<translation id="9059834730836941392">Runtuhkan pemberitahuan</translation>
<translation id="9150735707954472829">Tab</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_nl.xtb b/chromium/ui/strings/translations/ui_strings_nl.xtb
index dc29cdcc961..dbceceda99c 100644
--- a/chromium/ui/strings/translations/ui_strings_nl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_nl.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 dag geleden}other{# dagen geleden}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 minuut geleden}other{# minuten geleden}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 m}other{# m}}</translation>
+<translation id="1181037720776840403">Verwijderen</translation>
<translation id="1243314992276662751">Uploaden</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Pijl-omlaag</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dagen}}</translation>
<translation id="335581015389089642">Spraak</translation>
+<translation id="3462241349431650993">Als je de suggestie verbergt, wordt deze niet meer weergegeven via je account op al je apparaten.</translation>
<translation id="3479552764303398839">Niet nu</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag resterend}other{# dagen resterend}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">'<ph name="LOOKUP_STRING" />' opzoeken</translation>
<translation id="364720409959344976">Map voor uploaden selecteren</translation>
<translation id="3660179305079774227">Pijl-omhoog</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 seconde geleden}other{# seconden geleden}}</translation>
<translation id="654149438358937226">Alle meldingen blokkeren</translation>
<translation id="6567071839949112727">klik via bovenliggende entiteit</translation>
+<translation id="6578407462441924264">Naamloos</translation>
<translation id="6612467943526193239">Druk op Esc om de kalibratie af te sluiten.</translation>
<translation id="6620110761915583480">Bestand opslaan</translation>
<translation id="6699343763173986273">Volgende track voor media</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 uur geleden}other{# uur geleden}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sec. resterend}other{# sec. resterend}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automatisch aanvullen</translation>
<translation id="815598010540052116">Omlaag bladeren</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Pagina omlaag</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">Selecteren</translation>
<translation id="8393700583063109961">Bericht verzenden</translation>
<translation id="8394908167088220973">Media afspelen/onderbreken</translation>
+<translation id="8420205633584771378">Deze suggestie verwijderen?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 j}other{# j}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" />-bestand (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Knop Terug</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">openen</translation>
-<translation id="9038489124413477075">Naamloze map</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 sec.}other{# sec.}}</translation>
<translation id="9059834730836941392">Melding samenvouwen</translation>
<translation id="9150735707954472829">Tabblad</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_no.xtb b/chromium/ui/strings/translations/ui_strings_no.xtb
index 7e7f3827a42..e04e5fe5a43 100644
--- a/chromium/ui/strings/translations/ui_strings_no.xtb
+++ b/chromium/ui/strings/translations/ui_strings_no.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{For 1 dag siden}other{For # dager siden}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{for 1 minutt siden}other{for # minutter siden}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 m}other{# m}}</translation>
+<translation id="1181037720776840403">Fjern</translation>
<translation id="1243314992276662751">Last opp</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Pil ned</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dager}}</translation>
<translation id="335581015389089642">Tale</translation>
+<translation id="3462241349431650993">Hvis du skjuler dette forslaget, vises det ikke for kontoen din igjen på noen av enhetene dine.</translation>
<translation id="3479552764303398839">Ikke nå</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag igjen}other{# dager igjen}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Slå opp «<ph name="LOOKUP_STRING" />»</translation>
<translation id="364720409959344976">Velg mappen du vil laste opp</translation>
<translation id="3660179305079774227">Pil opp</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{for 1 sekund siden}other{for # sekunder siden}}</translation>
<translation id="654149438358937226">Blokkér alle varsler</translation>
<translation id="6567071839949112727">klikk på et overordnet element</translation>
+<translation id="6578407462441924264">Uten navn</translation>
<translation id="6612467943526193239">For å lukke kalibreringen, trykk på Esc.</translation>
<translation id="6620110761915583480">Lagre fil</translation>
<translation id="6699343763173986273">Media – neste spor</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{For 1 time siden}other{For # timer siden}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sek igjen}other{# sek igjen}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, autofullføring</translation>
<translation id="815598010540052116">Rull ned</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Ned 1 s.</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">merk av</translation>
<translation id="8393700583063109961">Send melding</translation>
<translation id="8394908167088220973">Media – spill av / pause</translation>
+<translation id="8420205633584771378">Vil du fjerne dette forslaget?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 år}other{# år}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> Fil (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB per sek</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Tilbakeknapp</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<translation id="9002566407876343676">åpne</translation>
-<translation id="9038489124413477075">Mappe uten navn</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 sek}other{# sek}}</translation>
<translation id="9059834730836941392">Skjul varselet</translation>
<translation id="9150735707954472829">Fane</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pl.xtb b/chromium/ui/strings/translations/ui_strings_pl.xtb
index 636702c11a5..b0df040db51 100644
--- a/chromium/ui/strings/translations/ui_strings_pl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pl.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 dzień temu}few{# dni temu}many{# dni temu}other{# dnia temu}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{minutę temu}few{# minuty temu}many{# minut temu}other{# minuty temu}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}few{# min}many{# min}other{# min}}</translation>
+<translation id="1181037720776840403">Usuń</translation>
<translation id="1243314992276662751">Prześlij</translation>
<translation id="1269641567813814718">Windows</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Jeśli ukryjesz tę sugestię, nie pojawi się ona ponownie na Twoim koncie na żadnym z Twoich urządzeń.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Sprawdź słowo „<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Wybierz folder do przesłania</translation>
<translation id="3660179305079774227">Strzałka w górę</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{sekundę temu}few{# sekundy temu}many{# sekund temu}other{# sekundy temu}}</translation>
<translation id="654149438358937226">Blokuj wszystkie powiadomienia</translation>
<translation id="6567071839949112727">kliknij element nadrzędny</translation>
+<translation id="6578407462441924264">Bez nazwy</translation>
<translation id="6612467943526193239">Aby zakończyć kalibrację, naciśnij Esc.</translation>
<translation id="6620110761915583480">Zapisz plik</translation>
<translation id="6699343763173986273">Następny utwór multimedialny</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 godzinę temu}few{# godziny temu}many{# godzin temu}other{# godziny temu}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Pozostała 1 s}few{Pozostały # s}many{Pozostało # s}other{Pozostało # s}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, autouzupełnianie</translation>
<translation id="815598010540052116">Przewiń w dół</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Strona w dół</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">zaznacz</translation>
<translation id="8393700583063109961">Wyślij wiadomość</translation>
<translation id="8394908167088220973">Odtwórz/wstrzymaj multimedia</translation>
+<translation id="8420205633584771378">Usunąć tę sugestię?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 rok}few{# lata}many{# lat}other{# roku}}</translation>
<translation id="8602707065186045623">Plik <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Przycisk Wstecz</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<translation id="9002566407876343676">otwórz</translation>
-<translation id="9038489124413477075">Folder bez nazwy</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}few{# s}many{# s}other{# s}}</translation>
<translation id="9059834730836941392">Zwiń powiadomienie</translation>
<translation id="9150735707954472829">Karta</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
index 62e68789939..429efbc616e 100644
--- a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Um dia atrás}one{# dias atrás}other{# dias atrás}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 minuto atrás}one{# minuto atrás}other{# minutos atrás}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}one{# min}other{# min}}</translation>
+<translation id="1181037720776840403">Remover</translation>
<translation id="1243314992276662751">Fazer upload</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Se você decidir ocultar esta sugestão, ela não será exibida novamente na sua conta em nenhum dos seus dispositivos.</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="3608915363409716668">+<ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Pesquisar “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Selecionar pasta para upload</translation>
<translation id="3660179305079774227">Seta para cima</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 segundo atrás}one{# segundo atrás}other{# segundos atrás}}</translation>
<translation id="654149438358937226">Bloquear todas as notificações</translation>
<translation id="6567071839949112727">clicar no predecessor</translation>
+<translation id="6578407462441924264">Sem nome</translation>
<translation id="6612467943526193239">Para sair da calibração pressione Esc.</translation>
<translation id="6620110761915583480">Salvar arquivo</translation>
<translation id="6699343763173986273">Próxima faixa da mídia</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Uma hora atrás}one{# horas atrás}other{# horas atrás}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 segundo restante}one{# segundos restantes}other{# segundos restantes}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, preenchimento automático</translation>
<translation id="815598010540052116">Percorrer para baixo</translation>
<translation id="8179976553408161302">Entrar</translation>
<translation id="8210608804940886430">Página para baixo</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">marcar</translation>
<translation id="8393700583063109961">Enviar mensagem</translation>
<translation id="8394908167088220973">Reproduzir/pausar mídia</translation>
+<translation id="8420205633584771378">Remover esta sugestão?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 a}one{# a}other{# a}}</translation>
<translation id="8602707065186045623">Arquivo <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Botão "Voltar"</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">abrir</translation>
-<translation id="9038489124413477075">Pasta sem nome</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}one{# s}other{# s}}</translation>
<translation id="9059834730836941392">Recolher notificação</translation>
<translation id="9150735707954472829">Guia</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
index 30810079c13..30009901995 100644
--- a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Há 1 dia}other{Há # dias}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Há 1 minuto}other{Há # minutos}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}other{# min}}</translation>
+<translation id="1181037720776840403">Remover</translation>
<translation id="1243314992276662751">Carregar</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Ao ocultar a sugestão, esta deixará de ser apresentada novamente na sua conta em todos os dispositivos.</translation>
<translation id="3479552764303398839">Agora não</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Falta 1 dia}other{Faltam # dias}}</translation>
+<translation id="3608915363409716668">Mais de <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Procurar "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Selecionar Pasta a Carregar</translation>
<translation id="3660179305079774227">Seta para cima</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Há 1 segundo}other{Há # segundos}}</translation>
<translation id="654149438358937226">Bloquear todas as notificações</translation>
<translation id="6567071839949112727">clicar no predecessor</translation>
+<translation id="6578407462441924264">Sem nome</translation>
<translation id="6612467943526193239">Para sair da calibração, prima Esc.</translation>
<translation id="6620110761915583480">Guardar ficheiro</translation>
<translation id="6699343763173986273">Faixa seguinte de multimédia</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Há 1 hora}other{Há # horas}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Falta 1 s}other{Faltam # s}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, preenchimento automático</translation>
<translation id="815598010540052116">Deslocar-se para baixo</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Página para baixo</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">verificar</translation>
<translation id="8393700583063109961">Enviar mensagem</translation>
<translation id="8394908167088220973">Reproduzir/interromper multimédia</translation>
+<translation id="8420205633584771378">Pretende remover esta sugestão?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 a}other{# a}}</translation>
<translation id="8602707065186045623">Ficheiro <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Botão Anterior</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">abrir</translation>
-<translation id="9038489124413477075">Pasta sem nome</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 seg}other{# seg}}</translation>
<translation id="9059834730836941392">Reduzir notificação</translation>
<translation id="9150735707954472829">Tabulação</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ro.xtb b/chromium/ui/strings/translations/ui_strings_ro.xtb
index a800ec1fb0c..13c5722f14c 100644
--- a/chromium/ui/strings/translations/ui_strings_ro.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ro.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Acum o zi}few{Acum # zile}other{Acum # de zile}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Acum 1 minut}few{Acum # minute}other{Acum # de minute}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min.}few{# min.}other{# min.}}</translation>
+<translation id="1181037720776840403">Elimină</translation>
<translation id="1243314992276662751">Încărcați</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Dacă ascunzi sugestia, nu se va mai afișa în cont pe niciun dispozitiv.</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="3608915363409716668">peste <ph name="MAXIMUM_VALUE" /></translation>
<translation id="3618849550573277856">Caută „<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Selectați un dosar de încărcat</translation>
<translation id="3660179305079774227">Săgeată în sus</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Acum 1 secundă}few{Acum # secunde}other{Acum # de secunde}}</translation>
<translation id="654149438358937226">Blochează toate notificările</translation>
<translation id="6567071839949112727">dă clic pe predecesor</translation>
+<translation id="6578407462441924264">Nedenumit</translation>
<translation id="6612467943526193239">Pentru a ieși din calibrare, apasă pe Esc.</translation>
<translation id="6620110761915583480">Salvează fișierul</translation>
<translation id="6699343763173986273">Melodia următoare din conținutul media</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Acum o oră}few{Acum # ore}other{Acum # de ore}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{O sec. rămasă}few{# sec. rămase}other{# sec. rămase}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, completare automată</translation>
<translation id="815598010540052116">Derulează în jos</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">O pagină mai jos</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">bifează</translation>
<translation id="8393700583063109961">Trimite un mesaj</translation>
<translation id="8394908167088220973">Redați/întrerupeți conținutul media</translation>
+<translation id="8420205633584771378">Eliminați această sugestie?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 an}few{# ani}other{# ani}}</translation>
<translation id="8602707065186045623">Fișier <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KO/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Butonul Înapoi</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KO</translation>
<translation id="9002566407876343676">deschide</translation>
-<translation id="9038489124413477075">Dosar fără nume</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{O sec.}few{# sec.}other{# sec.}}</translation>
<translation id="9059834730836941392">Restrânge notificarea</translation>
<translation id="9150735707954472829">Filă</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ru.xtb b/chromium/ui/strings/translations/ui_strings_ru.xtb
index 718d1bb9567..a8aed508542 100644
--- a/chromium/ui/strings/translations/ui_strings_ru.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ru.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 день назад}one{# день назад}few{# дня назад}many{# дней назад}other{# дня назад}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{минуту назад}one{# минуту назад}few{# минуты назад}many{# минут назад}other{# минуты назад}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 мин.}one{# мин.}few{# мин.}many{# мин.}other{# мин.}}</translation>
+<translation id="1181037720776840403">Удалить</translation>
<translation id="1243314992276662751">Загрузить</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Стрелка вниз</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 день}one{# день}few{# дня}many{# дней}other{# дня}}</translation>
<translation id="335581015389089642">Озвучить</translation>
+<translation id="3462241349431650993">Если вы скроете эту подсказку, то больше не увидите ее из своего аккаунта на устройствах, которыми пользуетесь.</translation>
<translation id="3479552764303398839">Не сейчас</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Остался 1 день}one{Остался # день}few{Осталось # дня}many{Осталось # дней}other{Осталось # дня}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Найти "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Выберите папку для загрузки</translation>
<translation id="3660179305079774227">Стрелка вверх</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{только что}one{# секунду назад}few{# секунды назад}many{# секунд назад}other{# секунды назад}}</translation>
<translation id="654149438358937226">Блокировать все уведомления</translation>
<translation id="6567071839949112727">нажмите на родительский элемент</translation>
+<translation id="6578407462441924264">Без имени</translation>
<translation id="6612467943526193239">Чтобы выйти из режима калибровки, нажмите ESC</translation>
<translation id="6620110761915583480">Сохранить файл</translation>
<translation id="6699343763173986273">Следующий трек</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 час назад}one{# час назад}few{# часа назад}many{# часов назад}other{# часа назад}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Осталась 1 сек.}one{Осталась # сек.}few{Осталось # сек.}many{Осталось # сек.}other{Осталось # сек.}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, автозаполнение</translation>
<translation id="815598010540052116">Прокрутка вниз</translation>
<translation id="8179976553408161302">ВВОД</translation>
<translation id="8210608804940886430">Прокрутка вниз</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">поставить галочку</translation>
<translation id="8393700583063109961">Отправить сообщение</translation>
<translation id="8394908167088220973">Воспроизведение/пауза</translation>
+<translation id="8420205633584771378">Удалить эту подсказку?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 г.}one{# г.}few{# г.}many{# л.}other{# г.}}</translation>
<translation id="8602707065186045623">Файл <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> КБ/с</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Назад</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> КБ</translation>
<translation id="9002566407876343676">открыть</translation>
-<translation id="9038489124413477075">Без названия</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 сек.}one{# сек.}few{# сек.}many{# сек.}other{# сек.}}</translation>
<translation id="9059834730836941392">Свернуть уведомление</translation>
<translation id="9150735707954472829">Вкладка</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sk.xtb b/chromium/ui/strings/translations/ui_strings_sk.xtb
index 55aae547510..3ab92189020 100644
--- a/chromium/ui/strings/translations/ui_strings_sk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sk.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Včera}few{Pred # dňami}many{Pred # dňom}other{Pred # dňami}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{pred minútou}few{pred # minútami}many{pred # minútami}other{pred # minútami}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}few{# min}many{# min}other{# min}}</translation>
+<translation id="1181037720776840403">Odstrániť</translation>
<translation id="1243314992276662751">Nahrať</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Ak tento návrh skryjete, nebude sa viac zobrazovať vo vašom účte vo všetkých vašich zariadeniach.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" /> a viac</translation>
<translation id="3618849550573277856">Vyhľadať „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Výber priečinka na nahranie</translation>
<translation id="3660179305079774227">Šípka nahor</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{pred sekundou}few{pred # sekundami}many{pred # sekundami}other{pred # sekundami}}</translation>
<translation id="654149438358937226">Blokovať všetky upozornenia</translation>
<translation id="6567071839949112727">kliknúť na nadradený objekt</translation>
+<translation id="6578407462441924264">Bez názvu</translation>
<translation id="6612467943526193239">Kalibráciu ukončíte stlačením klávesa Esc.</translation>
<translation id="6620110761915583480">Uložiť súbor</translation>
<translation id="6699343763173986273">Média – ďalšia stopa</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Pred 1 hodinou}few{Pred # hodinami}many{Pred # hodinou}other{Pred # hodinami}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Zostáva 1 s}few{Zostávajú # s}many{Zostáva # s}other{Zostáva # s}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, automatické dopĺňanie</translation>
<translation id="815598010540052116">Rolovať nadol</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Stránkovať nadol</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">označiť</translation>
<translation id="8393700583063109961">Odoslať správu</translation>
<translation id="8394908167088220973">Média – prehrať / pozastaviť</translation>
+<translation id="8420205633584771378">Chcete odstrániť tento návrh?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 r.}few{# r.}many{# r.}other{# r.}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> Súbor (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Tlačidlo Späť</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<translation id="9002566407876343676">otvorenie</translation>
-<translation id="9038489124413477075">Priečinok bez názvu</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}few{# s}many{# s}other{# s}}</translation>
<translation id="9059834730836941392">Zbaliť upozornenie</translation>
<translation id="9150735707954472829">Karta</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sl.xtb b/chromium/ui/strings/translations/ui_strings_sl.xtb
index 97b10ce46e3..e43bb2cc917 100644
--- a/chromium/ui/strings/translations/ui_strings_sl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sl.xtb
@@ -4,6 +4,7 @@
<translation id="111910763555783249">Nastavitve obvestil</translation>
<translation id="1127811143501539442">{DAYS,plural, =1{Pred 1 dnevom}one{Pred # dnevom}two{Pred # dnevoma}few{Pred # dnevi}other{Pred # dnevi}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Pred 1 minuto}one{Pred # minuto}two{Pred # minutama}few{Pred # minutami}other{Pred # minutami}}</translation>
+<translation id="1181037720776840403">Odstrani</translation>
<translation id="1243314992276662751">Prenesi</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -59,8 +60,10 @@
<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="3462241349431650993">Če skrijete ta predlog, ne bo več prikazan za vaš račun v vseh napravah.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Poišči »<ph name="LOOKUP_STRING" />«</translation>
<translation id="364720409959344976">Izberite mapo, ki jo želite prenesti</translation>
<translation id="3660179305079774227">Puščica gor</translation>
@@ -119,6 +122,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Pred 1 sekundo}one{Pred # sekundo}two{Pred # sekundama}few{Pred # sekundami}other{Pred # sekundami}}</translation>
<translation id="654149438358937226">Blokiraj vsa obvestila</translation>
<translation id="6567071839949112727">kliknite prednika</translation>
+<translation id="6578407462441924264">Neimenovano</translation>
<translation id="6612467943526193239">Če želite zapustiti umerjanje, pritisnite tipko Esc.</translation>
<translation id="6620110761915583480">Shrani datoteko</translation>
<translation id="6699343763173986273">Naslednja skladba</translation>
@@ -152,6 +156,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Pred 1 h}one{Pred # h}two{Pred # urama}few{Pred # urami}other{Pred # urami}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Še 1 s}one{Še # s}two{Še # s}few{Še # s}other{Še # s}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, samodokončanje</translation>
<translation id="815598010540052116">Pomik dol</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Stran dol</translation>
@@ -163,6 +168,7 @@
<translation id="838869780401515933">potrdi</translation>
<translation id="8393700583063109961">Pošlji sporočilo</translation>
<translation id="8394908167088220973">Ustavitev/začasna ustavitev</translation>
+<translation id="8420205633584771378">Želite odstraniti ta predlog?</translation>
<translation id="8602707065186045623">Datoteka <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
<translation id="8730621377337864115">Končano</translation>
@@ -172,7 +178,6 @@
<translation id="8841375032071747811">Gumb za nazaj</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">odpreti</translation>
-<translation id="9038489124413477075">Neimenovana mapa</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 s}one{# s}two{# s}few{# s}other{# s}}</translation>
<translation id="9059834730836941392">Strni obvestilo</translation>
<translation id="9150735707954472829">Zavihek</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sr.xtb b/chromium/ui/strings/translations/ui_strings_sr.xtb
index 642dbfd3d12..89d0082c9d2 100644
--- a/chromium/ui/strings/translations/ui_strings_sr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sr.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Пре 1 дан}one{Пре # дан}few{Пре # дана}other{Пре # дана}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Пре 1 минут}one{Пре # минут}few{Пре # минута}other{Пре # минута}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 м}one{# м}few{# м}other{# м}}</translation>
+<translation id="1181037720776840403">Уклони</translation>
<translation id="1243314992276662751">Отпреми</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Стрелица надоле</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 дан}one{# дан}few{# дана}other{# дана}}</translation>
<translation id="335581015389089642">Говор</translation>
+<translation id="3462241349431650993">Ако сакријете овај предлог, он се више неће приказивати на вашем налогу на свим уређајима.</translation>
<translation id="3479552764303398839">Не сада</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Још 1 дан}one{Још # дан}few{Још # дана}other{Још # дана}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Потражи „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Избор директоријума за отпремање</translation>
<translation id="3660179305079774227">Стрелица нагоре</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Пре 1 секунду}one{Пре # секунду}few{Пре # секунде}other{Пре # секунди}}</translation>
<translation id="654149438358937226">Блокирај сва обавештења</translation>
<translation id="6567071839949112727">кликните на претходни елемент</translation>
+<translation id="6578407462441924264">Без имена</translation>
<translation id="6612467943526193239">Да бисте изашли из калибрације, притисните Esc.</translation>
<translation id="6620110761915583480">Чување датотеке</translation>
<translation id="6699343763173986273">Следећа песма медија</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Пре 1 сат}one{Пре # сат}few{Пре # сата}other{Пре # сати}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Још 1 сек}one{Још # сек}few{Још # сек}other{Још # сек}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, аутоматско довршавање</translation>
<translation id="815598010540052116">Помери надоле</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Страница надоле</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">изабери</translation>
<translation id="8393700583063109961">Пошаљите поруку</translation>
<translation id="8394908167088220973">Пуштање/паузирање медија</translation>
+<translation id="8420205633584771378">Желите ли да уклоните овај предлог?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 г}one{# г}few{# г}other{# г}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> датотека (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Дугме Назад</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">отварање</translation>
-<translation id="9038489124413477075">Неименовани директоријум</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 сек}one{# сек}few{# сек}other{# сек}}</translation>
<translation id="9059834730836941392">Скупи обавештење</translation>
<translation id="9150735707954472829">Картица</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sv.xtb b/chromium/ui/strings/translations/ui_strings_sv.xtb
index b49a1c8f3e1..7a89387d8a8 100644
--- a/chromium/ui/strings/translations/ui_strings_sv.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sv.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{för 1 dag sedan}other{för # dagar sedan}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 minut sedan}other{# minuter sedan}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min}other{# min}}</translation>
+<translation id="1181037720776840403">Ta bort</translation>
<translation id="1243314992276662751">Ladda upp</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Nedpil</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dagar}}</translation>
<translation id="335581015389089642">Tal</translation>
+<translation id="3462241349431650993">Om du döljer förslaget visas det inte igen från kontot på någon av dina enheter</translation>
<translation id="3479552764303398839">Inte nu</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag kvar}other{# dagar kvar}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Sök efter ”<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Välj en mapp för uppladdning</translation>
<translation id="3660179305079774227">Uppil</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 sekund sedan}other{# sekunder sedan}}</translation>
<translation id="654149438358937226">Blockera alla aviseringar</translation>
<translation id="6567071839949112727">klicka på det överordnade objektet</translation>
+<translation id="6578407462441924264">Namnlös</translation>
<translation id="6612467943526193239">Tryck på Esc för att avsluta kalibreringen.</translation>
<translation id="6620110761915583480">Spara fil</translation>
<translation id="6699343763173986273">Nästa spår</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{för 1 timme sedan}other{för # timmar sedan}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sek kvar}other{# sek kvar}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, autoslutför</translation>
<translation id="815598010540052116">Rulla nedåt</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">kryssa för</translation>
<translation id="8393700583063109961">Skicka meddelande</translation>
<translation id="8394908167088220973">Spela upp/Pausa</translation>
+<translation id="8420205633584771378">Ska förslaget tas bort?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 år}other{# år}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" />-fil (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> kB/sek</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Bakåtknapp</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation>
<translation id="9002566407876343676">öppna</translation>
-<translation id="9038489124413477075">Namnlös mapp</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 sek}other{# sek}}</translation>
<translation id="9059834730836941392">Komprimera avisering</translation>
<translation id="9150735707954472829">Flik</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sw.xtb b/chromium/ui/strings/translations/ui_strings_sw.xtb
index 9e57408f9f4..b5255ecfd95 100644
--- a/chromium/ui/strings/translations/ui_strings_sw.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sw.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{Siku 1 iliyopita}other{Siku # zilizopita}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{Dakika 1 iliyopita}other{Dakika # zilizopita}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{Dak 1}other{Dak #}}</translation>
+<translation id="1181037720776840403">Ondoa</translation>
<translation id="1243314992276662751">Pakia</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Mshale Chini</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{Siku 1}other{Siku #}}</translation>
<translation id="335581015389089642">Usemi</translation>
+<translation id="3462241349431650993">Hatua ya kuficha pendekezo hili haitalionyesha tena kwenye akaunti yako katika vifaa vyako vyote.</translation>
<translation id="3479552764303398839">Sio sasa</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Imesalia siku 1}other{Zimesalia siku #}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Angalia “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Chagua Folda ya Kupakia</translation>
<translation id="3660179305079774227">Mshale Juu</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{Sekunde 1 iliyopita}other{Sekunde # zilizopita}}</translation>
<translation id="654149438358937226">Zuia arifa zote</translation>
<translation id="6567071839949112727">bofya kipengee</translation>
+<translation id="6578407462441924264">Isiyo na jina</translation>
<translation id="6612467943526193239">Ili kuacha kupima, bonyeza Esc.</translation>
<translation id="6620110761915583480">Hifadhi Faili</translation>
<translation id="6699343763173986273">Wimbo Unaofuata kwenye Media</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{Saa 1 iliyopita}other{Saa # zilizopita}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Imesalia sekunde 1}other{Zimesalia sekunde #}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, Jaza kiotomatiki</translation>
<translation id="815598010540052116">Sogeza Chini</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Ukurasa mmoja chini</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">chunguza</translation>
<translation id="8393700583063109961">Tuma ujumbe</translation>
<translation id="8394908167088220973">Cheza Media/Sitisha</translation>
+<translation id="8420205633584771378">Je, ungependa kuondoa pendekezo hili?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{Mwaka 1}other{Miaka #}}</translation>
<translation id="8602707065186045623">Faili ya <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Kitufe cha Nyuma</translation>
<translation id="8901569739625249689">KB <ph name="QUANTITY" /></translation>
<translation id="9002566407876343676">fungua</translation>
-<translation id="9038489124413477075">Folda isiyo na jina</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{Sekunde 1}other{Sekunde #}}</translation>
<translation id="9059834730836941392">Kunja arifa</translation>
<translation id="9150735707954472829">Kichupo</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ta.xtb b/chromium/ui/strings/translations/ui_strings_ta.xtb
index 8b052d21557..eb4f23bc83f 100644
--- a/chromium/ui/strings/translations/ui_strings_ta.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ta.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 நாள் முன்பு}other{# நாட்கள் உள்ளன}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 நிமிடத்திற்கு முன்பு}other{# நிமிடங்களுக்கு முன்பு}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1நி}other{#நி}}</translation>
+<translation id="1181037720776840403">அகற்று</translation>
<translation id="1243314992276662751">பதிவேற்று</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">கீழ்நோக்கிய அம்பு</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 நாள்}other{# நாட்கள்}}</translation>
<translation id="335581015389089642">பேச்சு</translation>
+<translation id="3462241349431650993">இந்தப் பரிந்துரையை மறைத்தால், இனி அது உங்கள் எல்லா சாதனங்களிலும் உங்கள் கணக்கிற்கு மீண்டும் காண்பிக்கப்படாது.</translation>
<translation id="3479552764303398839">இப்பொழுது இல்லை</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 நாள் உள்ளது}other{# நாட்கள் உள்ளன}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” எனத் தேடு</translation>
<translation id="364720409959344976">பதிவேற்றுவதற்குக் கோப்புறையைத் தேர்ந்தெடு</translation>
<translation id="3660179305079774227">மேல்நோக்கிய அம்பு</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 வினாடிக்கு முன்பு}other{# வினாடிகளுக்கு முன்பு}}</translation>
<translation id="654149438358937226">எல்லா அறிவிப்புகளையும் தடு</translation>
<translation id="6567071839949112727">ஆன்செஸ்டரைக் கிளிக் செய்</translation>
+<translation id="6578407462441924264">பெயரிடப்படாதது</translation>
<translation id="6612467943526193239">அளவுத்திருத்தத்திலிருந்து வெளியேற, Esc எனும் விசையை அழுத்தவும்.</translation>
<translation id="6620110761915583480">கோப்பைச் சேமி</translation>
<translation id="6699343763173986273">ஊடகத்தின் அடுத்த டிராக்</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 மணிநேரம் முன்பு}other{# மணிநேரம் முன்பு}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 நொடி உள்ளது}other{# நொடிகள் உள்ளன}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, தானே நிரப்பியது</translation>
<translation id="815598010540052116">கீழே உருட்டு</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">பக்கத்தின் கீழே</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">சரிபார்</translation>
<translation id="8393700583063109961">செய்தி அனுப்பு</translation>
<translation id="8394908167088220973">ஊடகத்தை இயக்கு/இடைநிறுத்து</translation>
+<translation id="8420205633584771378">இந்தப் பரிந்துரையை அகற்றவா?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1ஆ}other{#ஆ}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" />கோப்பு(.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> கி.பை./வி</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">முந்தையது பொத்தான்</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> கி.பை.</translation>
<translation id="9002566407876343676">திற</translation>
-<translation id="9038489124413477075">பெயரிடப்படாதக் கோப்புறை</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 நொடி}other{# நொடிகள்}}</translation>
<translation id="9059834730836941392">அறிவிப்பைச் சுருக்கு</translation>
<translation id="9150735707954472829">தாவல்</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_te.xtb b/chromium/ui/strings/translations/ui_strings_te.xtb
index c8e93a4a5f8..381b21ac069 100644
--- a/chromium/ui/strings/translations/ui_strings_te.xtb
+++ b/chromium/ui/strings/translations/ui_strings_te.xtb
@@ -5,12 +5,13 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 రోజు క్రితం}other{# రోజుల క్రితం}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 నిమిషం క్రితం}other{# నిమిషాల క్రితం}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1ని}other{#ని}}</translation>
+<translation id="1181037720776840403">తీసివేయి</translation>
<translation id="1243314992276662751">అప్‌లోడ్ చేయి</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
<translation id="1306549533752902673">సిఫార్సు చేసిన యాప్‌లు</translation>
<translation id="1368832886055348810">ఎడమ నుండి కుడికి</translation>
-<translation id="1383876407941801731">శోధించు</translation>
+<translation id="1383876407941801731">వెతుకు</translation>
<translation id="1398853756734560583">గరిష్ఠీకరించు</translation>
<translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> నుండి వచ్చే నోటిఫికేషన్‌లను నిలిపివేయి</translation>
<translation id="1591184457164800433">{MINUTES,plural, =1{1 నిమిషం మరియు }other{# నిమిషాలు మరియు }}</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">క్రింది బాణం</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 రోజు}other{# రోజులు}}</translation>
<translation id="335581015389089642">ప్రసంగం</translation>
+<translation id="3462241349431650993">ఈ సూచనను దాచడం వలన మీ అన్ని పరికరాలలో మీ ఖాతా నుండి ఇది మళ్లీ చూపబడదు.</translation>
<translation id="3479552764303398839">ఇప్పుడు కాదు</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 రోజు మిగిలి ఉంది}other{# రోజులు మిగిలి ఉన్నాయి}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />”ని వెతకండి</translation>
<translation id="364720409959344976">అప్‌లోడ్ చేయడానికి ఫోల్డర్‌ని ఎంచుకోండి</translation>
<translation id="3660179305079774227">ఎగువ బాణం</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 సెకను క్రితం}other{# సెకన్ల క్రితం}}</translation>
<translation id="654149438358937226">అన్ని నోటిఫికేషన్‌లను బ్లాక్ చేయి</translation>
<translation id="6567071839949112727">క్లిక్ మూలకం</translation>
+<translation id="6578407462441924264">పేరు లేదు</translation>
<translation id="6612467943526193239">క్రమాంకనం నుండి నిష్క్రమించేందుకు, Esc నొక్కండి.</translation>
<translation id="6620110761915583480">ఫైల్‌ను సేవ్ చేయి</translation>
<translation id="6699343763173986273">మీడియా తరువాత ట్రాక్</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 గంట క్రితం}other{# గంటల క్రితం}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 సెక. మిగిలి ఉంది}other{# సెక. మిగిలి ఉన్నాయి}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, స్వయంపూర్తి</translation>
<translation id="815598010540052116">క్రిందికి స్క్రోల్ చేయి</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">పేజీ క్రిందికి</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">తనిఖీ చేయి</translation>
<translation id="8393700583063109961">సందేశాన్ని పంపండి</translation>
<translation id="8394908167088220973">మీడియా ప్లే/పాజ్</translation>
+<translation id="8420205633584771378">ఈ సూచనని తీసివేయలా?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1సం}other{#సం}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> ఫైల్ (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/సె</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">వెనుకకు బటన్</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">తెరువు</translation>
-<translation id="9038489124413477075">పేరులేని ఫోల్డర్</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 సెక.}other{# సెక.}}</translation>
<translation id="9059834730836941392">నోటిఫికేషన్‌ను కుదించు</translation>
<translation id="9150735707954472829">ట్యాబ్</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_th.xtb b/chromium/ui/strings/translations/ui_strings_th.xtb
index e9e24a31832..0cc67fc6d2c 100644
--- a/chromium/ui/strings/translations/ui_strings_th.xtb
+++ b/chromium/ui/strings/translations/ui_strings_th.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 วันที่ผ่านมา}other{# วันที่ผ่านมา}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 นาทีที่ผ่านมา}other{# นาทีที่ผ่านมา}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 นาที}other{# นาที}}</translation>
+<translation id="1181037720776840403">นำออก</translation>
<translation id="1243314992276662751">อัปโหลด</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">ลูกศรลง</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 วัน}other{# วัน}}</translation>
<translation id="335581015389089642">คำพูด</translation>
+<translation id="3462241349431650993">การซ่อนคำแนะนำนี้จะทำให้คำแนะนำไม่แสดงจากบัญชีของคุณในอุปกรณ์ทุกเครื่องอีก</translation>
<translation id="3479552764303398839">ไม่ใช่ตอนนี้</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{เหลือ 1 วัน}other{เหลือ # วัน}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">ค้นหา “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">เลือกโฟลเดอร์เพื่ออัปโหลด</translation>
<translation id="3660179305079774227">ลูกศรขึ้น</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{ 1 วินาทีที่ผ่านมา}other{# วินาทีที่ผ่านมา}}</translation>
<translation id="654149438358937226">บล็อกการแจ้งเตือนทั้งหมด</translation>
<translation id="6567071839949112727">คลิกต้นตระกูล</translation>
+<translation id="6578407462441924264">ไม่ได้ตั้งชื่อ</translation>
<translation id="6612467943526193239">หากต้องการออกจากการปรับเทียบ ให้กด Esc</translation>
<translation id="6620110761915583480">บันทึกไฟล์</translation>
<translation id="6699343763173986273">แทร็กถัดไปของสื่อ</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 ชั่วโมงที่ผ่านมา}other{# ชั่วโมงที่ผ่านมา}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{เหลือ 1 วินาที}other{เหลือ # วินาที}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" /> เติมข้อความอัตโนมัติ</translation>
<translation id="815598010540052116">เลื่อนลง</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">เลื่อนหน้าลง</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">ทำเครื่องหมาย</translation>
<translation id="8393700583063109961">ส่งข้อความ</translation>
<translation id="8394908167088220973">เล่น/หยุดสื่อชั่วคราว</translation>
+<translation id="8420205633584771378">นำคำแนะนำนี้ออกไหม</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 ปี}other{# ปี}}</translation>
<translation id="8602707065186045623">ไฟล์ <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/วินาที</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">ปุ่มกลับ</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">เปิด</translation>
-<translation id="9038489124413477075">โฟลเดอร์ที่ไม่มีชื่อ</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 วินาที}other{# วินาที}}</translation>
<translation id="9059834730836941392">ยุบการแจ้งเตือน</translation>
<translation id="9150735707954472829">แท็บ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_tr.xtb b/chromium/ui/strings/translations/ui_strings_tr.xtb
index 4fbb78c1c22..11325279f69 100644
--- a/chromium/ui/strings/translations/ui_strings_tr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_tr.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 gün önce}other{# gün önce}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 dakika önce}other{# dakika önce}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 dk.}other{# dk.}}</translation>
+<translation id="1181037720776840403">Kaldır</translation>
<translation id="1243314992276662751">Yükle</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Bu öneriyi gizlerseniz, öneri bir daha cihazlarınızın hiçbirinde hesabınızdan gösterilmez.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" /> +</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” Araması Yap</translation>
<translation id="364720409959344976">Yüklenecek Klasörü Seçin</translation>
<translation id="3660179305079774227">Yukarı Ok</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 saniye önce}other{# saniye önce}}</translation>
<translation id="654149438358937226">Tüm bildirimleri engelle</translation>
<translation id="6567071839949112727">üst öğeyi tıkla</translation>
+<translation id="6578407462441924264">Adsız</translation>
<translation id="6612467943526193239">Kalibrasyondan çıkmak için Esc tuşuna basın.</translation>
<translation id="6620110761915583480">Dosyayı Kaydet</translation>
<translation id="6699343763173986273">Medya Sonraki Parça</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 saat önce}other{# saat önce}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sn. kaldı}other{# sn. kaldı}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, Otomatik tamamlama</translation>
<translation id="815598010540052116">Aşağı Kaydır</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">işaretle</translation>
<translation id="8393700583063109961">İleti gönder</translation>
<translation id="8394908167088220973">Medyayı Oynat/Duraklat</translation>
+<translation id="8420205633584771378">Bu öneri kaldırılsın mı?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 yıl}other{# yıl}}</translation>
<translation id="8602707065186045623">Dosyayı <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/sn</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Geri düğmesi</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">açma</translation>
-<translation id="9038489124413477075">Adsız Klasör</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 sn.}other{# sn.}}</translation>
<translation id="9059834730836941392">Bildirimi daralt</translation>
<translation id="9150735707954472829">Sekme</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_uk.xtb b/chromium/ui/strings/translations/ui_strings_uk.xtb
index c316037fcfd..e391aabdfa6 100644
--- a/chromium/ui/strings/translations/ui_strings_uk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_uk.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 день тому}one{# день тому}few{# дні тому}many{# днів тому}other{# дня тому}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 хвилину тому}one{# хвилину тому}few{# хвилини тому}many{# хвилин тому}other{# хвилини тому}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 хв}one{# хв}few{# хв}many{# хв}other{# хв}}</translation>
+<translation id="1181037720776840403">Видалити</translation>
<translation id="1243314992276662751">Завантажити</translation>
<translation id="1269641567813814718">Win</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">Курсор униз</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 день}one{# день}few{# дні}many{# днів}other{# дня}}</translation>
<translation id="335581015389089642">Speech</translation>
+<translation id="3462241349431650993">Якщо сховати цю пропозицію, вона більше не з’являтиметься у вашому обліковому записі на всіх ваших пристроях.</translation>
<translation id="3479552764303398839">Не зараз</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Залишився 1 день}one{Залишився # день}few{Залишилося # дні}many{Залишилося # днів}other{Залишилося # дня}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Шукати "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Виберіть папку для завантаження</translation>
<translation id="3660179305079774227">Курсор угору</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 секунду тому}one{# секунду тому}few{# секунди тому}many{# секунд тому}other{# секунди тому}}</translation>
<translation id="654149438358937226">Блокувати всі сповіщення</translation>
<translation id="6567071839949112727">натиснути предок</translation>
+<translation id="6578407462441924264">Без назви</translation>
<translation id="6612467943526193239">Натисніть клавішу Esc, щоб вийти з режиму калібрування.</translation>
<translation id="6620110761915583480">Зберегти файл</translation>
<translation id="6699343763173986273">Наступна композиція</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 годину тому}one{# годину тому}few{# години тому}many{# годин тому}other{# години тому}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Залишилась 1 с}one{Залишилася # с}few{Залишилося # с}many{Залишилося # с}other{Залишилося # с}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />: автозавершення</translation>
<translation id="815598010540052116">Прокрутка вниз</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Сторінка вниз</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">установити прапорець</translation>
<translation id="8393700583063109961">Надіслати повідомлення</translation>
<translation id="8394908167088220973">Відтворити чи призупинити</translation>
+<translation id="8420205633584771378">Видалити цю пропозицію?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 р.}one{# р.}few{# р.}many{# р.}other{# р.}}</translation>
<translation id="8602707065186045623">файл <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> КБ/сек.</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Кнопка "Назад"</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> КБ</translation>
<translation id="9002566407876343676">відкрити</translation>
-<translation id="9038489124413477075">Папка без назви</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 с}one{# с}few{# с}many{# с}other{# с}}</translation>
<translation id="9059834730836941392">Згорнути сповіщення</translation>
<translation id="9150735707954472829">Вкладка</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_vi.xtb b/chromium/ui/strings/translations/ui_strings_vi.xtb
index 9ce6b423e11..3f0411bca22 100644
--- a/chromium/ui/strings/translations/ui_strings_vi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_vi.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 ngày trước}other{# ngày trước}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 phút trước}other{# phút trước}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 phút}other{# phút}}</translation>
+<translation id="1181037720776840403">Xóa</translation>
<translation id="1243314992276662751">Tải lên</translation>
<translation id="1269641567813814718">Phím Win</translation>
<translation id="1293699935367580298">Thoát</translation>
@@ -63,8 +64,10 @@
<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="3462241349431650993">Nếu bạn ẩn nội dung đề xuất này, thì nội dung đề xuất này sẽ không hiển thị lại cho tài khoản của bạn trên tất cả các thiết bị.</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="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</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>
<translation id="3660179305079774227">Phím mũi tên Lên</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 giây trước}other{# giây trước}}</translation>
<translation id="654149438358937226">Chặn tất cả thông báo</translation>
<translation id="6567071839949112727">nhấp vào đối tượng cấp trên</translation>
+<translation id="6578407462441924264">Chưa đặt tên</translation>
<translation id="6612467943526193239">Để thoát chế độ hiệu chỉnh, nhấn Esc.</translation>
<translation id="6620110761915583480">Lưu Tệp</translation>
<translation id="6699343763173986273">Bản nhạc tiếp theo của trình phát phương tiện</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 giờ trước}other{# giờ trước}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Còn 1 giây}other{Còn # giây}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />, Tự động hoàn thành</translation>
<translation id="815598010540052116">Cuộn Xuống</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Trang Dưới</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">chọn</translation>
<translation id="8393700583063109961">Gửi tin nhắn</translation>
<translation id="8394908167088220973">Phát/Tạm dừng trình phát phương tiện</translation>
+<translation id="8420205633584771378">Xóa đề xuất này?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 năm}other{# năm}}</translation>
<translation id="8602707065186045623">Tệp <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">Nút quay lại</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">mở</translation>
-<translation id="9038489124413477075">Thư mục không có tên</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 giây}other{# giây}}</translation>
<translation id="9059834730836941392">Thu gọn thông báo</translation>
<translation id="9150735707954472829">Tab</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
index c1d9d8271a7..af2c8805764 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 天前}other{# 天前}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 分钟前}other{# 分钟前}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 分钟}other{# 分钟}}</translation>
+<translation id="1181037720776840403">删除</translation>
<translation id="1243314992276662751">上传</translation>
<translation id="1269641567813814718">Win 键</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">向下箭头</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 天}other{# 天}}</translation>
<translation id="335581015389089642">语音</translation>
+<translation id="3462241349431650993">如果隐藏这项推荐内容,无论您使用任何设备,该内容都不会再显示在您的帐号中。</translation>
<translation id="3479552764303398839">以后再说</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{还剩 1 天}other{还剩 # 天}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">查询“<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">选择要上传的文件夹</translation>
<translation id="3660179305079774227">向上箭头</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation>
<translation id="654149438358937226">屏蔽所有通知</translation>
<translation id="6567071839949112727">点击祖先实体</translation>
+<translation id="6578407462441924264">未命名</translation>
<translation id="6612467943526193239">要退出校准模式,请按 Esc 键。</translation>
<translation id="6620110761915583480">保存文件</translation>
<translation id="6699343763173986273">媒体下一曲</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" />+<ph name="KEY_COMBO_NAME" /></translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 小时前}other{# 小时前}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{还剩 1 秒}other{还剩 # 秒}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />,自动填充</translation>
<translation id="815598010540052116">向下滚动</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">向下翻页</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">选中</translation>
<translation id="8393700583063109961">发送消息</translation>
<translation id="8394908167088220973">媒体播放/暂停</translation>
+<translation id="8420205633584771378">移除这项推荐内容?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 年}other{# 年}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> 文件 (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">“返回”按钮</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">打开</translation>
-<translation id="9038489124413477075">未命名的文件夹</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 秒}other{# 秒}}</translation>
<translation id="9059834730836941392">收起通知</translation>
<translation id="9150735707954472829">标签</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
index 0f39485f684..76b772302e0 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
@@ -5,6 +5,7 @@
<translation id="1127811143501539442">{DAYS,plural, =1{1 天前}other{# 天前}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{1 分鐘前}other{# 分鐘前}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 分鐘}other{# 分鐘}}</translation>
+<translation id="1181037720776840403">移除</translation>
<translation id="1243314992276662751">上傳</translation>
<translation id="1269641567813814718">Windows 鍵</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -63,8 +64,10 @@
<translation id="3234408098842461169">向下鍵</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 天}other{# 天}}</translation>
<translation id="335581015389089642">語音</translation>
+<translation id="3462241349431650993">如果隱藏這項建議,你所有裝置上的帳戶都不會再顯示這項建議。</translation>
<translation id="3479552764303398839">現在不要</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{還剩 1 天}other{還剩 # 天}}</translation>
+<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">查詢「<ph name="LOOKUP_STRING" />」</translation>
<translation id="364720409959344976">選取要上傳的資料夾</translation>
<translation id="3660179305079774227">向上鍵</translation>
@@ -125,6 +128,7 @@
<translation id="6483402905448010557">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation>
<translation id="654149438358937226">封鎖所有通知</translation>
<translation id="6567071839949112727">點選上層項目</translation>
+<translation id="6578407462441924264">未命名</translation>
<translation id="6612467943526193239">如要結束校正模式,請按下 Esc 鍵。</translation>
<translation id="6620110761915583480">儲存檔案</translation>
<translation id="6699343763173986273">下一首媒體曲目</translation>
@@ -159,6 +163,7 @@
<translation id="8087772101393322318"><ph name="KEY_MODIFIER_NAME" /> + <ph name="KEY_COMBO_NAME" /> 鍵</translation>
<translation id="8106081041558092062">{HOURS,plural, =1{1 小時前}other{# 小時前}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{還剩 1 秒}other{還剩 # 秒}}</translation>
+<translation id="8152264887680882389"><ph name="TEXT" />,自動完成</translation>
<translation id="815598010540052116">向下捲動</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">向下翻頁</translation>
@@ -170,6 +175,7 @@
<translation id="838869780401515933">選取</translation>
<translation id="8393700583063109961">傳送訊息</translation>
<translation id="8394908167088220973">媒體播放/暫停</translation>
+<translation id="8420205633584771378">要移除這項建議嗎?</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1 年}other{# 年}}</translation>
<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> 檔案 (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/秒</translation>
@@ -182,7 +188,6 @@
<translation id="8841375032071747811">返回按鈕</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">開啟</translation>
-<translation id="9038489124413477075">未命名的資料夾</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 秒}other{# 秒}}</translation>
<translation id="9059834730836941392">收合通知</translation>
<translation id="9150735707954472829">分頁</translation>
diff --git a/chromium/ui/strings/ui_strings.grd b/chromium/ui/strings/ui_strings.grd
index 146d3fe1988..1386a7c3d8e 100644
--- a/chromium/ui/strings/ui_strings.grd
+++ b/chromium/ui/strings/ui_strings.grd
@@ -589,7 +589,7 @@ need to be translated for each locale.-->
<message name="IDS_APP_COMMA_KEY" desc="Comma key">
Comma
</message>
- <message name="IDS_APP_PERIOD_KEY" desc="Period key">
+ <message name="IDS_APP_PERIOD_KEY" desc="Period key, which is used to denote the end of a sentence (and not an interval of time).">
Period
</message>
<message name="IDS_APP_MEDIA_NEXT_TRACK_KEY" desc="Media next track key">
@@ -780,7 +780,10 @@ need to be translated for each locale.-->
Back
</message>
<message name="IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER" desc="The placeholder text for app list folder name.">
- Unnamed Folder
+ Unnamed
+ </message>
+ <message name="IDS_APP_LIST_SEARCH_BOX_AUTOCOMPLETE" desc="The spoken feedback text for when the search box autocompletes a result">
+ <ph name="TEXT">$1<ex>typed text + autocomplete</ex></ph>, Autocomplete
</message>
<message name="IDS_APP_LIST_FOLDER_BUTTON_ACCESSIBILE_NAME" desc="The spoken feedback text for navigating to a folder button in top level app list">
Folder <ph name="folder_name">$1<ex>OEM Apps</ex></ph>
@@ -803,6 +806,15 @@ need to be translated for each locale.-->
<message name="IDS_APP_LIST_CLEAR_SEARCHBOX" desc="Tooltip for the button that clears all text from the search box in the app list.">
Clear searchbox text
</message>
+ <message name="IDS_REMOVE_ZERO_STATE_SUGGESTION_TITLE" desc="Titlebar of removing zero state suggestion confirmation dialog">
+ Remove this suggestion?
+ </message>
+ <message name="IDS_REMOVE_ZERO_STATE_SUGGESTION_DETAILS" desc="Detailed explanation message for removing zero state suggestion">
+ Hiding this suggestion will not show it again from your account across all your devices.
+ </message>
+ <message name="IDS_REMOVE_SUGGESTION_BUTTON_LABEL" desc="Remove suggestion button label">
+ Remove
+ </message>
<message name="IDS_APP_LIST_START_ASSISTANT" desc="Tooltip for the button that starts Google Assistant from the search box in the app list.">
Start Google Assistant
</message>
@@ -857,6 +869,11 @@ need to be translated for each locale.-->
<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>
+
+ <!-- Badging -->
+ <message name="IDS_SATURATED_BADGE_CONTENT" desc="The content to display when the application's badge is too large to display to indicate that the badge is more than a given maximum. This string should be as short as possible, preferably only one character beyond the content">
+ <ph name="MAXIMUM_VALUE">$1<ex>99</ex></ph>+
+ </message>
</messages>
</release>
</grit>
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn
index a1868f58cfc..ae38b8fa488 100644
--- a/chromium/ui/views/BUILD.gn
+++ b/chromium/ui/views/BUILD.gn
@@ -7,6 +7,8 @@ import("//build/config/features.gni")
import("//build/config/jumbo.gni")
import("//build/config/ui.gni")
import("//components/vector_icons/vector_icons.gni")
+import("//services/catalog/public/tools/catalog.gni")
+import("//services/service_manager/public/service_manifest.gni")
import("//testing/test.gni")
import("//ui/base/ui_features.gni")
import("//ui/ozone/ozone.gni")
@@ -44,8 +46,8 @@ aggregate_vector_icons("views_vector_icons") {
]
}
-buildflag_header("features") {
- header = "features.h"
+buildflag_header("buildflags") {
+ header = "buildflags.h"
flags =
[ "ENABLE_NATIVE_WINDOW_NAV_BUTTONS=$enable_native_window_nav_buttons" ]
}
@@ -193,6 +195,8 @@ jumbo_component("views") {
"focus/widget_focus_manager.h",
"layout/box_layout.h",
"layout/fill_layout.h",
+ "layout/flex_layout.h",
+ "layout/flex_layout_types.h",
"layout/grid_layout.h",
"layout/layout_manager.h",
"layout/layout_provider.h",
@@ -247,6 +251,8 @@ jumbo_component("views") {
"widget/widget_removals_observer.h",
"widget/widget_utils.h",
"widget/widget_utils_mac.h",
+ "window/caption_button_layout_constants.h",
+ "window/caption_button_types.h",
"window/client_view.h",
"window/custom_frame_view.h",
"window/dialog_client_view.h",
@@ -254,6 +260,7 @@ jumbo_component("views") {
"window/dialog_observer.h",
"window/frame_background.h",
"window/frame_buttons.h",
+ "window/frame_caption_button.h",
"window/hit_test_utils.h",
"window/native_frame_view.h",
"window/non_client_view.h",
@@ -386,6 +393,9 @@ jumbo_component("views") {
"focus/widget_focus_manager.cc",
"layout/box_layout.cc",
"layout/fill_layout.cc",
+ "layout/flex_layout.cc",
+ "layout/flex_layout_types.cc",
+ "layout/flex_layout_types_internal.cc",
"layout/grid_layout.cc",
"layout/layout_manager.cc",
"layout/layout_provider.cc",
@@ -432,11 +442,13 @@ jumbo_component("views") {
"widget/widget_deletion_observer.cc",
"widget/widget_utils.cc",
"widget/widget_utils_mac.mm",
+ "window/caption_button_layout_constants.cc",
"window/client_view.cc",
"window/custom_frame_view.cc",
"window/dialog_client_view.cc",
"window/dialog_delegate.cc",
"window/frame_background.cc",
+ "window/frame_caption_button.cc",
"window/hit_test_utils.cc",
"window/native_frame_view.cc",
"window/non_client_view.cc",
@@ -470,6 +482,8 @@ jumbo_component("views") {
"cocoa/bridged_native_widget_host_impl.mm",
"cocoa/drag_drop_client_mac.h",
"cocoa/drag_drop_client_mac.mm",
+ "cocoa/text_input_host.h",
+ "cocoa/text_input_host.mm",
"cocoa/tooltip_manager_mac.h",
"cocoa/tooltip_manager_mac.mm",
"controls/button/label_button_label.cc",
@@ -478,18 +492,11 @@ jumbo_component("views") {
]
sources += get_target_outputs(":views_vector_icons")
-
- configs += [
- "//build/config:precompiled_headers",
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- "//build/config/compiler:no_size_t_to_int_warning",
- ]
-
+ configs += [ "//build/config:precompiled_headers" ]
defines = [ "VIEWS_IMPLEMENTATION" ]
deps = [
- ":features",
+ ":buildflags",
"//base:i18n",
"//base/third_party/dynamic_annotations",
"//cc/paint",
@@ -498,6 +505,7 @@ jumbo_component("views") {
"//skia",
"//third_party/icu",
"//ui/accessibility",
+ "//ui/base/clipboard",
"//ui/display",
"//ui/native_theme",
"//ui/native_theme:native_theme_browser",
@@ -513,6 +521,7 @@ jumbo_component("views") {
"//components/vector_icons",
"//ui/accessibility:ax_enums_mojo",
"//ui/base",
+ "//ui/base/clipboard",
"//ui/base/ime",
"//ui/compositor",
"//ui/display",
@@ -604,8 +613,10 @@ jumbo_component("views") {
if (use_aura) {
public += [
+ "accessibility/accessibility_alert_window.h",
"accessibility/ax_aura_obj_cache.h",
"accessibility/ax_aura_obj_wrapper.h",
+ "accessibility/ax_aura_window_utils.h",
"accessibility/ax_root_obj_wrapper.h",
"accessibility/ax_tree_source_views.h",
"accessibility/ax_view_obj_wrapper.h",
@@ -638,8 +649,10 @@ jumbo_component("views") {
]
sources += [
+ "accessibility/accessibility_alert_window.cc",
"accessibility/ax_aura_obj_cache.cc",
"accessibility/ax_aura_obj_wrapper.cc",
+ "accessibility/ax_aura_window_utils.cc",
"accessibility/ax_root_obj_wrapper.cc",
"accessibility/ax_tree_source_views.cc",
"accessibility/ax_view_obj_wrapper.cc",
@@ -670,6 +683,7 @@ jumbo_component("views") {
"widget/desktop_aura/desktop_native_widget_aura.cc",
"widget/desktop_aura/desktop_screen.cc",
"widget/desktop_aura/desktop_screen_position_client.cc",
+ "widget/desktop_aura/desktop_window_tree_host.cc",
"widget/focus_manager_event_handler.cc",
"widget/native_widget_aura.cc",
"widget/tooltip_manager_aura.cc",
@@ -788,7 +802,7 @@ jumbo_component("views") {
}
}
-jumbo_source_set("test_support_internal") {
+jumbo_source_set("test_support") {
testonly = true
sources = [
"animation/test/flood_fill_ink_drop_ripple_test_api.cc",
@@ -829,7 +843,11 @@ jumbo_source_set("test_support_internal") {
"test/menu_runner_test_api.h",
"test/menu_test_utils.cc",
"test/menu_test_utils.h",
+ "test/native_widget_factory.cc",
"test/native_widget_factory.h",
+ "test/platform_test_helper.cc",
+ "test/platform_test_helper.h",
+ "test/platform_test_helper_cocoa.mm",
"test/scoped_views_test_helper.cc",
"test/scoped_views_test_helper.h",
"test/slider_test_api.cc",
@@ -864,15 +882,10 @@ jumbo_source_set("test_support_internal") {
"views_test_suite.h",
]
- # External code should depend upon "test_support".
- visibility = [ "./*" ]
-
configs += [ "//build/config:precompiled_headers" ]
- public_deps = [
- ":views",
- ]
deps = [
+ ":views",
"//base",
"//base/test:test_support",
"//gpu/ipc/service",
@@ -882,6 +895,7 @@ jumbo_source_set("test_support_internal") {
"//testing/gtest",
"//ui/base",
"//ui/base:test_support",
+ "//ui/base/clipboard:clipboard_test_support",
"//ui/base/ime",
"//ui/compositor",
"//ui/compositor:test_support",
@@ -894,11 +908,32 @@ jumbo_source_set("test_support_internal") {
"//ui/gl:test_support",
]
- sources += [
- "test/platform_test_helper.cc",
- "test/platform_test_helper.h",
- "test/platform_test_helper_cocoa.mm",
- ]
+ if (enable_mus) {
+ sources += [
+ "test/platform_test_helper_mus.cc",
+ "test/platform_test_helper_mus.h",
+ ]
+
+ deps += [
+ ":views_unittests_catalog_source",
+ "//services/catalog:lib",
+ "//services/service_manager/background:lib",
+ "//services/service_manager/public/cpp",
+ "//services/service_manager/public/mojom",
+ "//services/ws/common",
+ "//testing/gtest",
+ "//ui/compositor:test_support",
+ "//ui/gl:test_support",
+ "//ui/resources",
+ "//ui/resources:ui_test_pak",
+ ]
+
+ data_deps = [
+ ":views_unittests_catalog",
+ "//services/ws/ime/test_ime_driver",
+ "//ui/resources:ui_test_pak_data",
+ ]
+ }
if (use_aura) {
sources += [
@@ -944,21 +979,7 @@ jumbo_source_set("test_support_internal") {
}
}
-jumbo_static_library("test_support") {
- testonly = true
- public_deps = [
- ":test_support_internal",
- ]
- sources = [
- "test/native_widget_factory_desktop.cc",
- ]
-}
-
-# This target contains the unit tests that are shared between views_unittests
-# and views_mus_unittests.
-source_set("views_unittests_sources") {
- testonly = true
-
+test("views_unittests") {
sources = [
"accessible_pane_view_unittest.cc",
"animation/bounds_animator_unittest.cc",
@@ -1013,15 +1034,18 @@ source_set("views_unittests_sources") {
"controls/table/test_table_model.cc",
"controls/table/test_table_model.h",
"controls/textfield/textfield_model_unittest.cc",
+ "controls/textfield/textfield_unittest.cc",
"controls/tree/tree_view_unittest.cc",
"event_monitor_unittest.cc",
"focus/focus_manager_unittest.cc",
"focus/focus_traversal_unittest.cc",
"layout/box_layout_unittest.cc",
"layout/fill_layout_unittest.cc",
+ "layout/flex_layout_unittest.cc",
"layout/grid_layout_unittest.cc",
"paint_info_unittest.cc",
"rect_based_targeting_utils_unittest.cc",
+ "run_all_unittests_main.cc",
"selection_controller_unittest.cc",
"test/widget_test_unittest.cc",
"view_model_unittest.cc",
@@ -1031,6 +1055,7 @@ source_set("views_unittests_sources") {
"view_unittest.cc",
"view_unittest_mac.mm",
"widget/ax_native_widget_mac_unittest.mm",
+ "widget/desktop_widget_unittest.cc",
"widget/native_widget_mac_unittest.mm",
"widget/native_widget_unittest.cc",
"widget/root_view_unittest.cc",
@@ -1038,6 +1063,7 @@ source_set("views_unittests_sources") {
"window/custom_frame_view_unittest.cc",
"window/dialog_client_view_unittest.cc",
"window/dialog_delegate_unittest.cc",
+ "window/frame_caption_button_unittest.cc",
"window/hit_test_utils_unittest.cc",
"window/non_client_view_unittest.cc",
"window/window_resize_utils_unittest.cc",
@@ -1045,10 +1071,8 @@ source_set("views_unittests_sources") {
configs += [ "//build/config:precompiled_headers" ]
- # Make all deps in this target public so both views_unittests and
- # views_mus_unittests will get them.
- public_deps = [
- ":test_support_internal",
+ deps = [
+ ":test_support",
":views",
"//base",
"//base:i18n",
@@ -1056,6 +1080,8 @@ source_set("views_unittests_sources") {
"//cc",
"//cc/paint",
"//components/vector_icons",
+ "//components/viz/common",
+ "//mojo/core/embedder",
"//services/ws/public/mojom",
"//skia",
"//testing/gtest",
@@ -1063,6 +1089,7 @@ source_set("views_unittests_sources") {
"//ui/accessibility",
"//ui/base",
"//ui/base:test_support",
+ "//ui/base/clipboard",
"//ui/base/ime",
"//ui/compositor:test_support",
"//ui/events:dom_keycode_converter",
@@ -1073,6 +1100,8 @@ source_set("views_unittests_sources") {
"//ui/gfx/geometry",
"//ui/gl:test_support",
"//ui/native_theme",
+ "//ui/native_theme:test_support",
+ "//ui/platform_window/platform_window_handler",
"//ui/resources",
"//ui/resources:ui_test_pak",
"//ui/strings",
@@ -1083,8 +1112,29 @@ source_set("views_unittests_sources") {
"//ui/resources:ui_test_pak_data",
]
+ if (enable_mus) {
+ sources += [
+ "mus/ax_remote_host_unittest.cc",
+ "mus/ax_tree_source_mus_unittest.cc",
+ "mus/desktop_window_tree_host_mus_unittest.cc",
+ "mus/screen_mus_unittest.cc",
+ ]
+
+ deps += [
+ "//services/ws/test_ws:mojom",
+ "//ui/accessibility/mojom",
+ "//ui/views/mus",
+ "//ui/views/mus/remote_view:tests",
+ ]
+
+ data_deps += [
+ "//services/ws/ime/test_ime_driver",
+ "//services/ws/test_ws",
+ ]
+ }
+
if (is_win) {
- public_deps += [
+ public_deps = [
"//build/win:default_exe_manifest",
"//third_party/iaccessible2",
"//third_party/wtl",
@@ -1109,102 +1159,71 @@ source_set("views_unittests_sources") {
]
}
- if (use_x11) {
- configs += [
- "//build/config/linux:x11",
- "//build/config/linux:xext",
- ]
- public_deps += [
- "//ui/events/devices",
- "//ui/events/platform/x11",
- "//ui/gfx/x",
+ if (is_mac) {
+ # views_unittests not yet compiling on Mac. http://crbug.com/378134
+ sources -= [ "controls/native/native_view_host_unittest.cc" ]
+ public_deps = [
+ "//ui/accelerated_widget_mac",
+ "//ui/views_bridge_mac:views_bridge_mac",
]
}
if (use_aura) {
sources += [
"accessibility/ax_aura_obj_cache_unittest.cc",
+ "accessibility/ax_aura_window_utils_unittest.cc",
"accessibility/ax_tree_source_views_unittest.cc",
"controls/native/native_view_host_aura_unittest.cc",
"corewm/tooltip_controller_unittest.cc",
+ "touchui/touch_selection_controller_impl_unittest.cc",
"touchui/touch_selection_menu_runner_views_unittest.cc",
"view_unittest_aura.cc",
+ "widget/desktop_aura/desktop_focus_rules_unittest.cc",
+ "widget/desktop_aura/desktop_native_widget_aura_unittest.cc",
+ "widget/native_widget_aura_unittest.cc",
"widget/window_reorderer_unittest.cc",
]
- public_deps += [
+ deps += [
+ "//ui/accessibility:test_support",
"//ui/aura",
"//ui/aura:test_support",
"//ui/touch_selection",
"//ui/wm",
"//ui/wm/public",
]
- }
-
- if (is_mac) {
- # views_unittests not yet compiling on Mac. http://crbug.com/378134
- sources -= [ "controls/native/native_view_host_unittest.cc" ]
- public_deps += [
- "//ui/accelerated_widget_mac",
- "//ui/views_bridge_mac:views_bridge_mac",
- ]
- }
-}
-
-test("views_unittests") {
- sources = [
- "run_all_unittests_main.cc",
-
- # EventGenerator doesn't work well with IME in mus so this must not be in
- # the shared unit test sources.
- # crbug.com/615033 crbug.com/548407
- "controls/textfield/textfield_unittest.cc",
- ]
-
- if (use_aura) {
- sources += [
- # These tests are expecting a hierarchy as created by classic ash. They
- # are only useful for views_unittests, and not in views_mus_unittests.
- "touchui/touch_selection_controller_impl_unittest.cc",
- "widget/native_widget_aura_unittest.cc",
- ]
if (is_mac) {
# views_unittests not yet compiling on Mac. http://crbug.com/378134
sources -= [ "widget/window_reorderer_unittest.cc" ]
}
- if (!is_chromeos) {
- sources += [
- "widget/desktop_aura/desktop_focus_rules_unittest.cc",
- "widget/desktop_aura/desktop_native_widget_aura_unittest.cc",
+ if (use_x11) {
+ configs += [
+ "//build/config/linux:x11",
+ "//build/config/linux:xext",
]
+ deps += [
+ "//ui/events/devices",
+ "//ui/events/platform/x11",
+ "//ui/gfx/x",
+ ]
+ }
+
+ if (!is_chromeos) {
if (use_x11) {
sources += [
"widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc",
"widget/desktop_aura/desktop_screen_x11_unittest.cc",
"widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc",
]
+ } else if (is_linux) {
+ sources += [
+ "widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc",
+ "widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc",
+ ]
}
}
}
-
- if (is_linux && !is_chromeos && !use_x11) {
- sources += [
- "widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc",
- "widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc",
- ]
- }
-
- if (!is_chromeos) {
- sources += [ "widget/desktop_widget_unittest.cc" ]
- }
-
- deps = [
- ":test_support",
- ":views_unittests_sources",
- "//mojo/core/embedder",
- "//ui/platform_window/platform_window_handler",
- ]
}
# This target is added as a dependency of browser interactive_ui_tests. It must
@@ -1279,6 +1298,28 @@ source_set("views_interactive_ui_tests") {
if (is_chromeos) {
sources -= [ "corewm/desktop_capture_controller_unittest.cc" ]
}
+
+ if (enable_mus) {
+ sources += [
+ "mus/clipboard_unittest.cc",
+ "mus/drag_interactive_uitest.cc",
+ ]
+
+ deps += [
+ "//mojo/core/embedder",
+ "//services/ws/public/mojom",
+ "//testing/gmock",
+ "//ui/base/ime",
+ "//ui/base/mojo:lib",
+ "//ui/events:events_base",
+ "//ui/touch_selection",
+ "//ui/views/mus",
+ ]
+
+ data_deps = [
+ "//services/ws/test_ws",
+ ]
+ }
}
test("views_perftests") {
@@ -1289,6 +1330,7 @@ test("views_perftests") {
deps = [
":test_support",
+ ":views",
"//base/test:test_support",
"//cc/base:base",
"//mojo/core/embedder",
@@ -1301,3 +1343,35 @@ test("views_perftests") {
"//testing:run_perf_test",
]
}
+
+if (enable_mus) {
+ service_manifest("unittests_manifest") {
+ name = "views_unittests"
+ source = "unittests_manifest.json"
+ }
+
+ service_manifest("interactive_ui_tests_manifest") {
+ name = "interactive_ui_tests"
+ source = "interactive_ui_tests_manifest.json"
+ }
+
+ catalog("views_unittests_catalog") {
+ testonly = true
+
+ embedded_services = [
+ ":unittests_manifest",
+ ":interactive_ui_tests_manifest",
+ ]
+
+ standalone_services = [
+ "//services/ws/test_ws:manifest",
+ "//services/ws/ime/test_ime_driver:manifest",
+ ]
+ }
+
+ catalog_cpp_source("views_unittests_catalog_source") {
+ testonly = true
+ catalog = ":views_unittests_catalog"
+ generated_function_name = "views::CreateViewsUnittestsCatalog"
+ }
+}
diff --git a/chromium/ui/views/DEPS b/chromium/ui/views/DEPS
index a2d0ab1f98c..488eb2c2706 100644
--- a/chromium/ui/views/DEPS
+++ b/chromium/ui/views/DEPS
@@ -38,11 +38,21 @@ specific_include_rules = {
"views_perftests\.cc": [
"+mojo/core/embedder",
],
+ "views_test_base\.cc": [
+ "+mojo/core/embedder",
+ "+services/catalog",
+ "+services/service_manager/background",
+ "+services/service_manager/public",
+ "+services/ws",
+ "+ui/gl",
+ ],
"view_unittest\.cc": [
- "+cc/playback"
+ "+cc/playback",
+ "+components/viz/common",
],
"views_test_suite\.cc": [
"+gpu/ipc/service",
+ "+ui/gl",
],
".*test\.cc": [
"+cc/base",
diff --git a/chromium/ui/views/OWNERS b/chromium/ui/views/OWNERS
index 57c9ed66f82..9ebfacd64f8 100644
--- a/chromium/ui/views/OWNERS
+++ b/chromium/ui/views/OWNERS
@@ -13,4 +13,9 @@ per-file *.mm=ellyjones@chromium.org
# If you're doing structural changes get a review from one of the OWNERS.
per-file BUILD.gn=*
+per-file interactive_ui_tests_manifest.json=set noparent
+per-file interactive_ui_tests_manifest.json=file://ipc/SECURITY_OWNERS
+per-file unittests_manifest.json=set noparent
+per-file unittests_manifest.json=file://ipc/SECURITY_OWNERS
+
# COMPONENT: Internals>Views
diff --git a/chromium/ui/views/accessibility/accessibility_alert_window.cc b/chromium/ui/views/accessibility/accessibility_alert_window.cc
new file mode 100644
index 00000000000..28a46e9b890
--- /dev/null
+++ b/chromium/ui/views/accessibility/accessibility_alert_window.cc
@@ -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.
+
+#include "ui/views/accessibility/accessibility_alert_window.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer_type.h"
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/view_accessibility.h"
+
+namespace views {
+
+AccessibilityAlertWindow::AccessibilityAlertWindow(aura::Window* parent,
+ views::AXAuraObjCache* cache)
+ : cache_(cache) {
+ CHECK(parent);
+ alert_window_ = std::make_unique<aura::Window>(
+ nullptr, aura::client::WINDOW_TYPE_UNKNOWN, parent->env());
+ alert_window_->set_owned_by_parent(false);
+ alert_window_->Init(ui::LayerType::LAYER_NOT_DRAWN);
+ alert_window_->SetProperty(ui::kAXRoleOverride, ax::mojom::Role::kAlert);
+ parent->AddChild(alert_window_.get());
+ alert_window_->env()->AddObserver(this);
+}
+
+AccessibilityAlertWindow::~AccessibilityAlertWindow() {
+ if (alert_window_.get())
+ alert_window_->env()->RemoveObserver(this);
+}
+
+void AccessibilityAlertWindow::HandleAlert(const std::string& alert_string) {
+ if (!alert_window_->parent())
+ return;
+
+ alert_window_->SetTitle(base::UTF8ToUTF16(alert_string));
+ cache_->FireEvent(cache_->GetOrCreate(alert_window_.get()),
+ ax::mojom::Event::kAlert);
+}
+
+void AccessibilityAlertWindow::OnWindowInitialized(aura::Window* window) {}
+
+void AccessibilityAlertWindow::OnWillDestroyEnv() {
+ alert_window_.reset();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/accessibility_alert_window.h b/chromium/ui/views/accessibility/accessibility_alert_window.h
new file mode 100644
index 00000000000..3fbaa5b6ebf
--- /dev/null
+++ b/chromium/ui/views/accessibility/accessibility_alert_window.h
@@ -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.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_ACCESSIBILITY_ALERT_WINDOW_H_
+#define UI_VIEWS_ACCESSIBILITY_ACCESSIBILITY_ALERT_WINDOW_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "ui/aura/env_observer.h"
+#include "ui/views/views_export.h"
+
+namespace aura {
+class Window;
+}
+
+namespace views {
+class AXAuraObjCache;
+
+// This class provides a caller a way to alert an accessibility client such as
+// ChromeVox with a text string without a backing visible window or view.
+class VIEWS_EXPORT AccessibilityAlertWindow : public aura::EnvObserver {
+ public:
+ // |parent| is the window where a child alert window will be added.
+ AccessibilityAlertWindow(aura::Window* parent, views::AXAuraObjCache* cache);
+ ~AccessibilityAlertWindow() override;
+
+ // Triggers an alert with the text |alert_string| to be sent to an
+ // accessibility client.
+ void HandleAlert(const std::string& alert_string);
+
+ private:
+ // aura::EnvObserver:
+ void OnWindowInitialized(aura::Window* window) override;
+ void OnWillDestroyEnv() override;
+
+ // The child alert window.
+ std::unique_ptr<aura::Window> alert_window_;
+
+ // The accessibility cache associated with |alert_window_|.
+ views::AXAuraObjCache* cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityAlertWindow);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_ACCESSIBILITY_ALERT_WINDOW_H_
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
index 7c840f00b9a..268e227a0ad 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -4,12 +4,13 @@
#include "ui/views/accessibility/ax_aura_obj_cache.h"
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
#include "base/strings/string_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/accessibility/ax_aura_window_utils.h"
#include "ui/views/accessibility/ax_view_obj_wrapper.h"
#include "ui/views/accessibility/ax_widget_obj_wrapper.h"
#include "ui/views/accessibility/ax_window_obj_wrapper.h"
@@ -18,6 +19,7 @@
#include "ui/views/widget/widget_delegate.h"
namespace views {
+namespace {
aura::client::FocusClient* GetFocusClient(aura::Window* root_window) {
if (!root_window)
@@ -25,9 +27,12 @@ aura::client::FocusClient* GetFocusClient(aura::Window* root_window) {
return aura::client::GetFocusClient(root_window);
}
+} // namespace
+
// static
AXAuraObjCache* AXAuraObjCache::GetInstance() {
- return base::Singleton<AXAuraObjCache>::get();
+ static base::NoDestructor<AXAuraObjCache> instance;
+ return instance.get();
}
AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(View* view) {
@@ -92,10 +97,8 @@ AXAuraObjWrapper* AXAuraObjCache::Get(int32_t id) {
void AXAuraObjCache::GetTopLevelWindows(
std::vector<AXAuraObjWrapper*>* children) {
- for (const auto& it : window_to_id_map_) {
- if (!it.first->parent())
- children->push_back(GetOrCreate(it.first));
- }
+ for (aura::Window* root : root_windows_)
+ children->push_back(GetOrCreate(root));
}
AXAuraObjWrapper* AXAuraObjCache::GetFocus() {
@@ -119,10 +122,8 @@ void AXAuraObjCache::FireEvent(AXAuraObjWrapper* aura_obj,
AXAuraObjCache::AXAuraObjCache() = default;
-AXAuraObjCache::~AXAuraObjCache() {
- is_destroying_ = true;
- cache_.clear();
-}
+// Never runs because object is leaked.
+AXAuraObjCache::~AXAuraObjCache() = default;
View* AXAuraObjCache::GetFocusedView() {
Widget* focused_widget = focused_widget_for_testing_;
@@ -139,13 +140,15 @@ View* AXAuraObjCache::GetFocusedView() {
if (!focused_window)
return nullptr;
- focused_widget = Widget::GetWidgetForNativeView(focused_window);
+ // SingleProcessMash may need to jump between ash and client windows.
+ AXAuraWindowUtils* window_utils = AXAuraWindowUtils::Get();
+ focused_widget = window_utils->GetWidgetForNativeView(focused_window);
while (!focused_widget) {
focused_window = focused_window->parent();
if (!focused_window)
break;
- focused_widget = Widget::GetWidgetForNativeView(focused_window);
+ focused_widget = window_utils->GetWidgetForNativeView(focused_window);
}
}
@@ -207,7 +210,7 @@ AXAuraObjWrapper* AXAuraObjCache::CreateInternal(
if (it != aura_view_to_id_map.end())
return Get(it->second);
- auto wrapper = std::make_unique<AuraViewWrapper>(aura_view);
+ auto wrapper = std::make_unique<AuraViewWrapper>(this, aura_view);
int32_t id = wrapper->GetUniqueId();
aura_view_to_id_map[aura_view] = id;
cache_[id] = std::move(wrapper);
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.h b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
index 3a4a448e0ed..1bbcc3d1c9b 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.h
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
@@ -18,8 +18,9 @@
#include "ui/views/views_export.h"
namespace base {
-template <typename T> struct DefaultSingletonTraits;
-}
+template <typename T>
+class NoDestructor;
+} // namespace base
namespace aura {
class Window;
@@ -72,7 +73,8 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
// Lookup a cached entry based on an id.
AXAuraObjWrapper* Get(int32_t id);
- // Get all top level windows this cache knows about.
+ // Get all top level windows this cache knows about. Under classic ash and
+ // SingleProcessMash this is a list of per-display root windows.
void GetTopLevelWindows(std::vector<AXAuraObjWrapper*>* children);
// Get the object that has focus.
@@ -84,9 +86,6 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
// Tell our delegate to fire an event on a given object.
void FireEvent(AXAuraObjWrapper* aura_obj, ax::mojom::Event event_type);
- // Indicates if this object's currently being destroyed.
- bool is_destroying() { return is_destroying_; }
-
// Notifies this cache of a change in root window.
void OnRootWindowObjCreated(aura::Window* window);
@@ -103,7 +102,7 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
}
private:
- friend struct base::DefaultSingletonTraits<AXAuraObjCache>;
+ friend class base::NoDestructor<AXAuraObjCache>;
AXAuraObjCache();
~AXAuraObjCache() override;
@@ -134,9 +133,6 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
std::map<int32_t, std::unique_ptr<AXAuraObjWrapper>> cache_;
- // True immediately when entering this object's destructor.
- bool is_destroying_ = false;
-
Delegate* delegate_ = nullptr;
std::set<aura::Window*> root_windows_;
diff --git a/chromium/ui/views/accessibility/ax_aura_window_utils.cc b/chromium/ui/views/accessibility/ax_aura_window_utils.cc
new file mode 100644
index 00000000000..94607885483
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_aura_window_utils.cc
@@ -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.
+
+#include "ui/views/accessibility/ax_aura_window_utils.h"
+
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+namespace {
+AXAuraWindowUtils* g_instance = nullptr;
+}
+
+AXAuraWindowUtils::~AXAuraWindowUtils() = default;
+
+// static
+AXAuraWindowUtils* AXAuraWindowUtils::Get() {
+ if (!g_instance)
+ g_instance = new AXAuraWindowUtils();
+ return g_instance;
+}
+
+// static
+void AXAuraWindowUtils::Set(std::unique_ptr<AXAuraWindowUtils> new_instance) {
+ if (g_instance)
+ delete g_instance;
+ g_instance = new_instance.release();
+}
+
+aura::Window* AXAuraWindowUtils::GetParent(aura::Window* window) {
+ return window->parent();
+}
+
+aura::Window::Windows AXAuraWindowUtils::GetChildren(aura::Window* window) {
+ return window->children();
+}
+
+bool AXAuraWindowUtils::IsRootWindow(aura::Window* window) const {
+ return window->IsRootWindow();
+}
+
+views::Widget* AXAuraWindowUtils::GetWidgetForNativeView(aura::Window* window) {
+ return Widget::GetWidgetForNativeView(window);
+}
+
+AXAuraWindowUtils::AXAuraWindowUtils() = default;
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_aura_window_utils.h b/chromium/ui/views/accessibility/ax_aura_window_utils.h
new file mode 100644
index 00000000000..20df81f6be9
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_aura_window_utils.h
@@ -0,0 +1,43 @@
+// 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_AURA_WINDOW_UTILS_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_AURA_WINDOW_UTILS_H_
+
+#include "ui/aura/window.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+class Widget;
+
+// Singleton class that provides functions for walking a tree of aura::Windows
+// for accessibility. in particular, for --single-process-mash we want the
+// accessibility tree to jump from a proxy aura Window on the ash side direclty
+// to its corresponding client window. This is just a temporary solution to
+// that issue and should be removed once Mash is fully launched.
+// crbug.com/911945
+class VIEWS_EXPORT AXAuraWindowUtils {
+ public:
+ virtual ~AXAuraWindowUtils();
+
+ static AXAuraWindowUtils* Get();
+
+ // Replace this global instance with a subclass.
+ static void Set(std::unique_ptr<AXAuraWindowUtils> new_instance);
+
+ virtual aura::Window* GetParent(aura::Window* window);
+ virtual aura::Window::Windows GetChildren(aura::Window* window);
+ virtual bool IsRootWindow(aura::Window* window) const;
+ virtual views::Widget* GetWidgetForNativeView(aura::Window* window);
+
+ protected:
+ AXAuraWindowUtils();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AXAuraWindowUtils);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_AURA_WINDOW_UTILS_H_
diff --git a/chromium/ui/views/accessibility/ax_aura_window_utils_unittest.cc b/chromium/ui/views/accessibility/ax_aura_window_utils_unittest.cc
new file mode 100644
index 00000000000..ed33817179a
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_aura_window_utils_unittest.cc
@@ -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.
+
+#include "ui/views/accessibility/ax_aura_window_utils.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_id.h"
+#include "ui/accessibility/ax_tree_serializer.h"
+#include "ui/accessibility/ax_tree_source_checker.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/ax_tree_source_views.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace {
+
+bool HasNodeWithName(ui::AXNode* node, const std::string& name) {
+ if (node->GetStringAttribute(ax::mojom::StringAttribute::kName) == name)
+ return true;
+ for (auto* child : node->children()) {
+ if (HasNodeWithName(child, name))
+ return true;
+ }
+ return false;
+}
+
+bool HasNodeWithName(ui::AXTree* tree, const std::string& name) {
+ return HasNodeWithName(tree->root(), name);
+}
+
+// Subclass of AXAuraWindowUtils that skips any aura::Window named ParentWindow.
+class TestAXAuraWindowUtils : public AXAuraWindowUtils {
+ public:
+ TestAXAuraWindowUtils() {}
+ ~TestAXAuraWindowUtils() override {}
+
+ private:
+ aura::Window* GetParent(aura::Window* window) override {
+ aura::Window* parent = window->parent();
+ if (parent && parent->GetTitle() == base::ASCIIToUTF16("ParentWindow"))
+ return parent->parent();
+ return parent;
+ }
+
+ aura::Window::Windows GetChildren(aura::Window* window) override {
+ auto children = window->children();
+ if (children.size() == 1 &&
+ children[0]->GetTitle() == base::ASCIIToUTF16("ParentWindow"))
+ return children[0]->children();
+ return children;
+ }
+};
+
+using AuraAXTreeSerializer = ui::
+ AXTreeSerializer<views::AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData>;
+
+using AuraAXTreeSourceChecker =
+ ui::AXTreeSourceChecker<views::AXAuraObjWrapper*,
+ ui::AXNodeData,
+ ui::AXTreeData>;
+
+class AXAuraWindowUtilsTest : public ViewsTestBase {
+ public:
+ AXAuraWindowUtilsTest() = default;
+ ~AXAuraWindowUtilsTest() override = default;
+
+ void SetUp() override {
+ ViewsTestBase::SetUp();
+
+ parent_widget_ = std::make_unique<Widget>();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ parent_widget_->Init(params);
+ parent_widget_->GetNativeWindow()->SetTitle(
+ base::ASCIIToUTF16("ParentWindow"));
+ parent_widget_->Show();
+
+ child_widget_ = new Widget(); // Owned by parent_widget_.
+ params = CreateParams(Widget::InitParams::TYPE_BUBBLE);
+ params.parent = parent_widget_->GetNativeWindow();
+ params.child = true;
+ params.bounds = gfx::Rect(100, 100, 200, 200);
+ params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
+ child_widget_->Init(params);
+ auto* button = new LabelButton(nullptr, base::ASCIIToUTF16("ChildButton"));
+ button->SetSize(gfx::Size(20, 20));
+ child_widget_->GetContentsView()->AddChildView(button);
+ child_widget_->GetNativeWindow()->SetTitle(
+ base::ASCIIToUTF16("ChildWindow"));
+ child_widget_->Show();
+ }
+
+ void TearDown() override {
+ // Close and reset the parent widget. The child widget will be cleaned
+ // up automatically as it's owned by the parent widget.
+ if (!parent_widget_->IsClosed())
+ parent_widget_->CloseNow();
+ parent_widget_.reset();
+ ViewsTestBase::TearDown();
+ }
+
+ protected:
+ std::unique_ptr<ui::AXTree> GetAccessibilityTreeFromWindow(
+ aura::Window* window) {
+ ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
+ AXTreeSourceViews tree_source(cache->GetOrCreate(window), tree_id);
+ AuraAXTreeSerializer serializer(&tree_source);
+ ui::AXTreeUpdate serialized_tree;
+ serializer.SerializeChanges(tree_source.GetRoot(), &serialized_tree);
+
+ AuraAXTreeSourceChecker checker(&tree_source);
+ if (!checker.Check())
+ return std::make_unique<ui::AXTree>();
+
+ // For debugging, run with --v=1.
+ VLOG(1) << serialized_tree.ToString();
+
+ return std::make_unique<ui::AXTree>(serialized_tree);
+ }
+
+ std::unique_ptr<Widget> parent_widget_;
+ Widget* child_widget_ = nullptr;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AXAuraWindowUtilsTest);
+};
+
+TEST_F(AXAuraWindowUtilsTest, GetHierarchy) {
+ aura::Window* window = child_widget_->GetNativeWindow();
+ aura::Window* root = window->GetRootWindow();
+ std::unique_ptr<ui::AXTree> ax_tree = GetAccessibilityTreeFromWindow(root);
+
+ // For debugging, run with --v=1.
+ VLOG(1) << ax_tree->ToString();
+
+ EXPECT_TRUE(HasNodeWithName(ax_tree.get(), "ParentWindow"));
+ EXPECT_TRUE(HasNodeWithName(ax_tree.get(), "ChildWindow"));
+ EXPECT_TRUE(HasNodeWithName(ax_tree.get(), "ChildButton"));
+}
+
+TEST_F(AXAuraWindowUtilsTest, GetHierarchyWithTestAuraWindowUtils) {
+ // TestAXAuraWindowUtils will skip over an aura::Window
+ // with a title of "ParentWindow".
+ AXAuraWindowUtils::Set(std::make_unique<TestAXAuraWindowUtils>());
+
+ aura::Window* window = child_widget_->GetNativeWindow();
+ aura::Window* root = window->GetRootWindow();
+ std::unique_ptr<ui::AXTree> ax_tree = GetAccessibilityTreeFromWindow(root);
+
+ // For debugging, run with --v=1.
+ VLOG(1) << ax_tree->ToString();
+
+ EXPECT_FALSE(HasNodeWithName(ax_tree.get(), "ParentWindow"));
+ EXPECT_TRUE(HasNodeWithName(ax_tree.get(), "ChildWindow"));
+ EXPECT_TRUE(HasNodeWithName(ax_tree.get(), "ChildButton"));
+}
+
+} // namespace
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
index c9327cbb09a..3af0a2582eb 100644
--- a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
@@ -11,7 +11,6 @@
#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"
#include "ui/display/screen.h"
@@ -19,41 +18,14 @@
#include "ui/views/accessibility/ax_window_obj_wrapper.h"
AXRootObjWrapper::AXRootObjWrapper(views::AXAuraObjCache::Delegate* delegate)
- : alert_window_(std::make_unique<aura::Window>(nullptr)),
- delegate_(delegate) {
- alert_window_->Init(ui::LAYER_NOT_DRAWN);
-#if !defined(IS_CHROMECAST)
- aura::Env::GetInstance()->AddObserver(this);
-
+ : delegate_(delegate) {
if (display::Screen::GetScreen())
display::Screen::GetScreen()->AddObserver(this);
-#endif
}
AXRootObjWrapper::~AXRootObjWrapper() {
-#if !defined(IS_CHROMECAST)
if (display::Screen::GetScreen())
display::Screen::GetScreen()->RemoveObserver(this);
-
- // If alert_window_ is nullptr already, that means OnWillDestroyEnv
- // was already called, so we shouldn't call RemoveObserver(this) again.
- if (!alert_window_)
- return;
-
- aura::Env::GetInstance()->RemoveObserver(this);
-#endif
- alert_window_.reset();
-}
-
-views::AXAuraObjWrapper* AXRootObjWrapper::GetAlertForText(
- const std::string& text) {
- alert_window_->SetTitle(base::UTF8ToUTF16((text)));
- views::AXWindowObjWrapper* window_obj =
- static_cast<views::AXWindowObjWrapper*>(
- views::AXAuraObjCache::GetInstance()->GetOrCreate(
- alert_window_.get()));
- window_obj->set_is_alert(true);
- return window_obj;
}
bool AXRootObjWrapper::HasChild(views::AXAuraObjWrapper* child) {
@@ -73,21 +45,21 @@ views::AXAuraObjWrapper* AXRootObjWrapper::GetParent() {
void AXRootObjWrapper::GetChildren(
std::vector<views::AXAuraObjWrapper*>* out_children) {
views::AXAuraObjCache::GetInstance()->GetTopLevelWindows(out_children);
- out_children->push_back(
- views::AXAuraObjCache::GetInstance()->GetOrCreate(alert_window_.get()));
}
void AXRootObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
out_node_data->id = unique_id_.Get();
out_node_data->role = ax::mojom::Role::kDesktop;
-#if !defined(IS_CHROMECAST)
display::Screen* screen = display::Screen::GetScreen();
if (!screen)
return;
const display::Display& display = screen->GetPrimaryDisplay();
+ out_node_data->relative_bounds.bounds =
+ gfx::RectF(display.bounds().width(), display.bounds().height());
+
// Utilize the display bounds to figure out if this screen is in landscape or
// portrait. We use this rather than |rotation| because some devices default
// to landscape, some in portrait. Encode landscape as horizontal state,
@@ -96,7 +68,6 @@ void AXRootObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
out_node_data->AddState(ax::mojom::State::kHorizontal);
else
out_node_data->AddState(ax::mojom::State::kVertical);
-#endif
}
int32_t AXRootObjWrapper::GetUniqueId() const {
@@ -107,10 +78,3 @@ void AXRootObjWrapper::OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) {
delegate_->OnEvent(this, ax::mojom::Event::kLocationChanged);
}
-
-void AXRootObjWrapper::OnWindowInitialized(aura::Window* window) {}
-
-void AXRootObjWrapper::OnWillDestroyEnv() {
- alert_window_.reset();
- aura::Env::GetInstance()->RemoveObserver(this);
-}
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
index 7f0ca125bf6..67713fbd992 100644
--- a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
@@ -13,21 +13,16 @@
#include "base/macros.h"
#include "ui/accessibility/platform/ax_unique_id.h"
-#include "ui/aura/env_observer.h"
#include "ui/display/display_observer.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
class VIEWS_EXPORT AXRootObjWrapper : public views::AXAuraObjWrapper,
- display::DisplayObserver,
- aura::EnvObserver {
+ display::DisplayObserver {
public:
explicit AXRootObjWrapper(views::AXAuraObjCache::Delegate* delegate);
~AXRootObjWrapper() override;
- // Returns an AXAuraObjWrapper for an alert window with title set to |text|.
- views::AXAuraObjWrapper* GetAlertForText(const std::string& text);
-
// Convenience method to check for existence of a child.
bool HasChild(views::AXAuraObjWrapper* child);
@@ -44,14 +39,8 @@ class VIEWS_EXPORT AXRootObjWrapper : public views::AXAuraObjWrapper,
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) override;
- // aura::EnvObserver:
- void OnWindowInitialized(aura::Window* window) override;
- void OnWillDestroyEnv() override;
-
ui::AXUniqueId unique_id_;
- std::unique_ptr<aura::Window> alert_window_;
-
views::AXAuraObjCache::Delegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(AXRootObjWrapper);
diff --git a/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc b/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
index aa9e497e6b1..2060c8e0ed8 100644
--- a/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
+++ b/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
@@ -7,20 +7,16 @@
#include <wrl/client.h>
#include "base/macros.h"
-#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_variant.h"
-#include "mojo/core/embedder/embedder.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_edit_commands.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_paths.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gl/test/gl_surface_test_support.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_test_api.h"
@@ -31,21 +27,16 @@ namespace views {
namespace {
-class AXSystemCaretWinTest : public test::WidgetTest {
+class AXSystemCaretWinTest : public test::DesktopWidgetTest {
public:
AXSystemCaretWinTest() : self_(CHILDID_SELF) {}
~AXSystemCaretWinTest() override {}
void SetUp() override {
- mojo::core::Init();
- gl::GLSurfaceTestSupport::InitializeOneOff();
- ui::RegisterPathProvider();
- base::FilePath ui_test_pak_path;
- ASSERT_TRUE(base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
- ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
- test::WidgetTest::SetUp();
-
- widget_ = CreateNativeDesktopWidget();
+ SetUpForInteractiveTests();
+ test::DesktopWidgetTest::SetUp();
+
+ widget_ = CreateTopLevelNativeWidget();
widget_->SetBounds(gfx::Rect(0, 0, 200, 200));
textfield_ = new Textfield();
textfield_->SetBounds(0, 0, 200, 20);
@@ -63,7 +54,7 @@ class AXSystemCaretWinTest : public test::WidgetTest {
void TearDown() override {
widget_->CloseNow();
- test::WidgetTest::TearDown();
+ test::DesktopWidgetTest::TearDown();
ui::ResourceBundle::CleanupSharedInstance();
}
diff --git a/chromium/ui/views/accessibility/ax_tree_source_views.cc b/chromium/ui/views/accessibility/ax_tree_source_views.cc
index 7f9231b8c53..078a89f151f 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views.cc
+++ b/chromium/ui/views/accessibility/ax_tree_source_views.cc
@@ -17,6 +17,15 @@
namespace views {
+AXTreeSourceViews::AXTreeSourceViews(AXAuraObjWrapper* root,
+ const ui::AXTreeID& tree_id)
+ : root_(root), tree_id_(tree_id) {
+ DCHECK(root_);
+ DCHECK_NE(tree_id_, ui::AXTreeIDUnknown());
+}
+
+AXTreeSourceViews::~AXTreeSourceViews() = default;
+
void AXTreeSourceViews::HandleAccessibleAction(const ui::AXActionData& action) {
int id = action.target_node_id;
@@ -96,6 +105,12 @@ void AXTreeSourceViews::SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const {
node->Serialize(out_data);
+ if (out_data->role == ax::mojom::Role::kWindow ||
+ out_data->role == ax::mojom::Role::kDialog) {
+ // Add clips children flag by default to these roles.
+ out_data->AddBoolAttribute(ax::mojom::BoolAttribute::kClipsChildren, true);
+ }
+
// Converts the global coordinates reported by each AXAuraObjWrapper
// into parent-relative coordinates to be used in the accessibility
// tree. That way when any Window, Widget, or View moves (and fires
@@ -127,16 +142,4 @@ std::string AXTreeSourceViews::ToString(AXAuraObjWrapper* root,
return output;
}
-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 d7554c0abdf..0c110a77dd5 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views.h
+++ b/chromium/ui/views/accessibility/ax_tree_source_views.h
@@ -29,6 +29,9 @@ class VIEWS_EXPORT AXTreeSourceViews
: public ui::
AXTreeSource<AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData> {
public:
+ AXTreeSourceViews(AXAuraObjWrapper* root, const ui::AXTreeID& tree_id);
+ ~AXTreeSourceViews() override;
+
// Invokes an action on an Aura object.
void HandleAccessibleAction(const ui::AXActionData& action);
@@ -49,18 +52,12 @@ class VIEWS_EXPORT AXTreeSourceViews
// Useful for debugging.
std::string ToString(views::AXAuraObjWrapper* root, std::string prefix);
- protected:
- 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;
+ AXAuraObjWrapper* const root_ = nullptr;
// ID to use for the AX tree.
- ui::AXTreeID tree_id_;
+ const 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 05a8dcb682e..7ce02c4a1e9 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views_unittest.cc
+++ b/chromium/ui/views/accessibility/ax_tree_source_views_unittest.cc
@@ -26,9 +26,8 @@ namespace {
// TestAXTreeSourceViews provides a root with a default tree ID.
class TestAXTreeSourceViews : public AXTreeSourceViews {
public:
- TestAXTreeSourceViews(AXAuraObjWrapper* root) {
- Init(root, ui::AXTreeID::FromString("123"));
- }
+ TestAXTreeSourceViews(AXAuraObjWrapper* root)
+ : AXTreeSourceViews(root, ui::AXTreeID::CreateNewAXTreeID()) {}
~TestAXTreeSourceViews() override = default;
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
index d8c900efa8c..2100f6b361e 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -14,9 +14,10 @@
namespace views {
-AXViewObjWrapper::AXViewObjWrapper(View* view) : view_(view) {
+AXViewObjWrapper::AXViewObjWrapper(AXAuraObjCache* aura_obj_cache, View* view)
+ : aura_obj_cache_(aura_obj_cache), view_(view) {
if (view->GetWidget())
- AXAuraObjCache::GetInstance()->GetOrCreate(view->GetWidget());
+ aura_obj_cache_->GetOrCreate(view->GetWidget());
view->AddObserver(this);
}
@@ -35,12 +36,11 @@ AXAuraObjWrapper* AXViewObjWrapper::GetParent() {
if (!view_)
return nullptr;
- AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
if (view_->parent())
- return cache->GetOrCreate(view_->parent());
+ return aura_obj_cache_->GetOrCreate(view_->parent());
if (view_->GetWidget())
- return cache->GetOrCreate(view_->GetWidget());
+ return aura_obj_cache_->GetOrCreate(view_->GetWidget());
return nullptr;
}
@@ -58,8 +58,7 @@ void AXViewObjWrapper::GetChildren(
if (!view_->child_at(i)->visible())
continue;
- AXAuraObjWrapper* child =
- AXAuraObjCache::GetInstance()->GetOrCreate(view_->child_at(i));
+ AXAuraObjWrapper* child = aura_obj_cache_->GetOrCreate(view_->child_at(i));
out_children->push_back(child);
}
}
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
index 5a160307c47..545468ee300 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
@@ -12,12 +12,14 @@
#include "ui/views/view_observer.h"
namespace views {
+class AXAuraObjCache;
class View;
// Describes a |View| for use with other AX classes.
class AXViewObjWrapper : public AXAuraObjWrapper, public ViewObserver {
public:
- explicit AXViewObjWrapper(View* view);
+ // |aura_obj_cache| must outlive this object.
+ AXViewObjWrapper(AXAuraObjCache* aura_obj_cache, View* view);
~AXViewObjWrapper() override;
View* view() { return view_; }
@@ -34,6 +36,8 @@ class AXViewObjWrapper : public AXAuraObjWrapper, public ViewObserver {
void OnViewIsDeleting(View* observed_view) override;
private:
+ AXAuraObjCache* const aura_obj_cache_;
+
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
index f6519a599e2..31a322c13ac 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view.cc
+++ b/chromium/ui/views/accessibility/ax_virtual_view.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <utility>
+#include "base/callback.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_platform_node.h"
@@ -104,6 +105,7 @@ std::unique_ptr<AXVirtualView> AXVirtualView::RemoveChildView(
std::unique_ptr<AXVirtualView> child = std::move(children_[cur_index]);
children_.erase(children_.begin() + cur_index);
child->virtual_parent_view_ = nullptr;
+ child->populate_data_callback_.Reset();
return child;
}
@@ -159,6 +161,15 @@ ui::AXNodeData& AXVirtualView::GetCustomData() {
return custom_data_;
}
+void AXVirtualView::SetPopulateDataCallback(
+ base::RepeatingCallback<void(const View&, ui::AXNodeData*)> callback) {
+ populate_data_callback_ = std::move(callback);
+}
+
+void AXVirtualView::UnsetPopulateDataCallback() {
+ populate_data_callback_.Reset();
+}
+
// ui::AXPlatformNodeDelegate
const ui::AXNodeData& AXVirtualView::GetData() const {
@@ -175,6 +186,8 @@ const ui::AXNodeData& AXVirtualView::GetData() const {
if (GetOwnerView() && GetOwnerView()->context_menu_controller())
node_data.AddAction(ax::mojom::Action::kShowContextMenu);
+ if (populate_data_callback_ && GetOwnerView())
+ populate_data_callback_.Run(*GetOwnerView(), &node_data);
return node_data;
}
diff --git a/chromium/ui/views/accessibility/ax_virtual_view.h b/chromium/ui/views/accessibility/ax_virtual_view.h
index 73edd0b1666..02206520117 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view.h
+++ b/chromium/ui/views/accessibility/ax_virtual_view.h
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "ui/accessibility/ax_enums.mojom.h"
@@ -101,8 +102,16 @@ class VIEWS_EXPORT AXVirtualView : public ui::AXPlatformNodeDelegateBase {
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.
+ // Allows clients to modify the AXNodeData for this virtual view. This should
+ // be used for attributes that are relatively stable and do not change
+ // dynamically.
ui::AXNodeData& GetCustomData();
+ // Allows clients to modify the AXNodeData for this virtual view dynamically
+ // via a callback. This should be used for attributes that change often and
+ // would be queried every time a client accesses this view's AXNodeData.
+ void SetPopulateDataCallback(
+ base::RepeatingCallback<void(const View&, ui::AXNodeData*)> callback);
+ void UnsetPopulateDataCallback();
// ui::AXPlatformNodeDelegate
const ui::AXNodeData& GetData() const override;
@@ -160,6 +169,8 @@ class VIEWS_EXPORT AXVirtualView : public ui::AXPlatformNodeDelegateBase {
ui::AXUniqueId unique_id_;
ui::AXNodeData custom_data_;
+ base::RepeatingCallback<void(const View&, ui::AXNodeData*)>
+ populate_data_callback_;
friend class ViewAccessibility;
DISALLOW_COPY_AND_ASSIGN(AXVirtualView);
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
index e3cd96c1a75..2869557e43a 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -13,17 +13,16 @@
namespace views {
-AXWidgetObjWrapper::AXWidgetObjWrapper(Widget* widget) : widget_(widget) {
+AXWidgetObjWrapper::AXWidgetObjWrapper(AXAuraObjCache* aura_obj_cache,
+ Widget* widget)
+ : aura_obj_cache_(aura_obj_cache), widget_(widget) {
widget->AddObserver(this);
widget->AddRemovalsObserver(this);
}
AXWidgetObjWrapper::~AXWidgetObjWrapper() {
- if (!AXAuraObjCache::GetInstance()->is_destroying()) {
- widget_->RemoveObserver(this);
- widget_->RemoveRemovalsObserver(this);
- }
- widget_ = NULL;
+ widget_->RemoveObserver(this);
+ widget_->RemoveRemovalsObserver(this);
}
bool AXWidgetObjWrapper::IsIgnored() {
@@ -31,7 +30,7 @@ bool AXWidgetObjWrapper::IsIgnored() {
}
AXAuraObjWrapper* AXWidgetObjWrapper::GetParent() {
- return AXAuraObjCache::GetInstance()->GetOrCreate(widget_->GetNativeView());
+ return aura_obj_cache_->GetOrCreate(widget_->GetNativeView());
}
void AXWidgetObjWrapper::GetChildren(
@@ -41,8 +40,7 @@ void AXWidgetObjWrapper::GetChildren(
return;
}
- out_children->push_back(
- AXAuraObjCache::GetInstance()->GetOrCreate(widget_->GetRootView()));
+ out_children->push_back(aura_obj_cache_->GetOrCreate(widget_->GetRootView()));
}
void AXWidgetObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
@@ -52,6 +50,8 @@ void AXWidgetObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
ax::mojom::StringAttribute::kName,
base::UTF16ToUTF8(
widget_->widget_delegate()->GetAccessibleWindowTitle()));
+ out_node_data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "Widget");
out_node_data->relative_bounds.bounds =
gfx::RectF(widget_->GetWindowBoundsInScreen());
out_node_data->state = 0;
@@ -62,21 +62,21 @@ int32_t AXWidgetObjWrapper::GetUniqueId() const {
}
void AXWidgetObjWrapper::OnWidgetDestroying(Widget* widget) {
- AXAuraObjCache::GetInstance()->Remove(widget);
+ aura_obj_cache_->Remove(widget);
}
void AXWidgetObjWrapper::OnWidgetClosing(Widget* widget) {
- AXAuraObjCache::GetInstance()->Remove(widget);
+ aura_obj_cache_->Remove(widget);
}
void AXWidgetObjWrapper::OnWidgetVisibilityChanged(Widget*, bool) {
// If a widget changes visibility it may affect what's focused, in particular
// when a widget that contains the focused view gets hidden.
- AXAuraObjCache::GetInstance()->OnFocusedViewChanged();
+ aura_obj_cache_->OnFocusedViewChanged();
}
void AXWidgetObjWrapper::OnWillRemoveView(Widget* widget, View* view) {
- AXAuraObjCache::GetInstance()->RemoveViewSubtree(view);
+ aura_obj_cache_->RemoveViewSubtree(view);
}
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
index 283efcb7b12..080c21a86f4 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
@@ -14,6 +14,7 @@
#include "ui/views/widget/widget_removals_observer.h"
namespace views {
+class AXAuraObjCache;
class Widget;
// Describes a |Widget| for use with other AX classes.
@@ -21,7 +22,8 @@ class AXWidgetObjWrapper : public AXAuraObjWrapper,
public WidgetObserver,
public WidgetRemovalsObserver {
public:
- explicit AXWidgetObjWrapper(Widget* widget);
+ // |aura_obj_cache| must outlive this object.
+ AXWidgetObjWrapper(AXAuraObjCache* aura_obj_cache, Widget* widget);
~AXWidgetObjWrapper() override;
// AXAuraObjWrapper overrides.
@@ -40,6 +42,8 @@ class AXWidgetObjWrapper : public AXAuraObjWrapper,
void OnWillRemoveView(Widget* widget, View* view) override;
private:
+ AXAuraObjCache* const aura_obj_cache_;
+
Widget* widget_;
const ui::AXUniqueId unique_id_;
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
index 91c4ef7e03d..7b260c24142 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -14,47 +14,48 @@
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/ax_aura_window_utils.h"
#include "ui/views/widget/widget.h"
namespace views {
+namespace {
-// 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), event_type);
-
+Widget* GetWidgetForWindow(aura::Window* window) {
Widget* widget = Widget::GetWidgetForNativeView(window);
- if (widget) {
- AXAuraObjCache::GetInstance()->FireEvent(
- AXAuraObjCache::GetInstance()->GetOrCreate(widget), event_type);
-
- views::View* root_view = widget->GetRootView();
- if (root_view)
- root_view->NotifyAccessibilityEvent(event_type, true);
+ if (!widget)
+ return nullptr;
+
+ // Under mus/mash both the WindowTreeHost's root aura::Window and the content
+ // aura::Window will return the same Widget for GetWidgetForNativeView(). Only
+ // return the Widget for the content window, not the root, since otherwise
+ // we'll end up with two children in the AX node tree that have the same
+ // parent.
+ if (widget->GetNativeWindow() != window) {
+ DCHECK(window->IsRootWindow());
+ return nullptr;
}
- aura::Window::Windows children = window->children();
- for (size_t i = 0; i < children.size(); ++i)
- FireEvent(children[i], ax::mojom::Event::kLocationChanged);
+ return widget;
}
-AXWindowObjWrapper::AXWindowObjWrapper(aura::Window* window)
- : window_(window),
- is_alert_(false),
- is_root_window_(window->IsRootWindow()) {
+} // namespace
+
+AXWindowObjWrapper::AXWindowObjWrapper(AXAuraObjCache* aura_obj_cache,
+ aura::Window* window)
+ : aura_obj_cache_(aura_obj_cache),
+ window_(window),
+ is_root_window_(AXAuraWindowUtils::Get()->IsRootWindow(window)) {
window->AddObserver(this);
if (is_root_window_)
- AXAuraObjCache::GetInstance()->OnRootWindowObjCreated(window);
+ aura_obj_cache_->OnRootWindowObjCreated(window);
}
AXWindowObjWrapper::~AXWindowObjWrapper() {
if (is_root_window_)
- AXAuraObjCache::GetInstance()->OnRootWindowObjDestroyed(window_);
+ aura_obj_cache_->OnRootWindowObjDestroyed(window_);
window_->RemoveObserver(this);
- window_ = NULL;
}
bool AXWindowObjWrapper::IsIgnored() {
@@ -62,24 +63,25 @@ bool AXWindowObjWrapper::IsIgnored() {
}
AXAuraObjWrapper* AXWindowObjWrapper::GetParent() {
- if (!window_->parent())
- return NULL;
+ aura::Window* parent = AXAuraWindowUtils::Get()->GetParent(window_);
+ if (!parent)
+ return nullptr;
- return AXAuraObjCache::GetInstance()->GetOrCreate(window_->parent());
+ return aura_obj_cache_->GetOrCreate(parent);
}
void AXWindowObjWrapper::GetChildren(
std::vector<AXAuraObjWrapper*>* out_children) {
- aura::Window::Windows children = window_->children();
+ aura::Window::Windows children =
+ AXAuraWindowUtils::Get()->GetChildren(window_);
for (size_t i = 0; i < children.size(); ++i) {
- out_children->push_back(
- AXAuraObjCache::GetInstance()->GetOrCreate(children[i]));
+ out_children->push_back(aura_obj_cache_->GetOrCreate(children[i]));
}
// Also consider any associated widgets as children.
- Widget* widget = Widget::GetWidgetForNativeView(window_);
+ Widget* widget = GetWidgetForWindow(window_);
if (widget && widget->IsVisible())
- out_children->push_back(AXAuraObjCache::GetInstance()->GetOrCreate(widget));
+ out_children->push_back(aura_obj_cache_->GetOrCreate(widget));
}
void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
@@ -88,8 +90,7 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
if (role != ax::mojom::Role::kNone)
out_node_data->role = role;
else
- out_node_data->role =
- is_alert_ ? ax::mojom::Role::kAlert : ax::mojom::Role::kWindow;
+ out_node_data->role = ax::mojom::Role::kWindow;
out_node_data->AddStringAttribute(ax::mojom::StringAttribute::kName,
base::UTF16ToUTF8(window_->GetTitle()));
if (!window_->IsVisible())
@@ -107,13 +108,19 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
// To avoid this double-parenting, only add the child tree ID of this
// window if the top-level window doesn't have an associated Widget.
if (!window_->GetToplevelWindow() ||
- Widget::GetWidgetForNativeView(window_->GetToplevelWindow())) {
+ GetWidgetForWindow(window_->GetToplevelWindow())) {
return;
}
out_node_data->AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
*child_ax_tree_id_ptr);
}
+
+ std::string class_name = window_->GetName();
+ if (class_name.empty())
+ class_name = "aura::Window";
+ out_node_data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ class_name);
}
int32_t AXWindowObjWrapper::GetUniqueId() const {
@@ -121,19 +128,19 @@ int32_t AXWindowObjWrapper::GetUniqueId() const {
}
void AXWindowObjWrapper::OnWindowDestroyed(aura::Window* window) {
- AXAuraObjCache::GetInstance()->Remove(window, nullptr);
+ aura_obj_cache_->Remove(window, nullptr);
}
void AXWindowObjWrapper::OnWindowDestroying(aura::Window* window) {
- Widget* widget = Widget::GetWidgetForNativeView(window);
+ Widget* widget = GetWidgetForWindow(window);
if (widget)
- AXAuraObjCache::GetInstance()->Remove(widget);
+ aura_obj_cache_->Remove(widget);
}
void AXWindowObjWrapper::OnWindowHierarchyChanged(
const HierarchyChangeParams& params) {
if (params.phase == WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED)
- AXAuraObjCache::GetInstance()->Remove(params.target, params.old_parent);
+ aura_obj_cache_->Remove(params.target, params.old_parent);
}
void AXWindowObjWrapper::OnWindowBoundsChanged(
@@ -151,15 +158,13 @@ void AXWindowObjWrapper::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
if (window == window_ && key == ui::kChildAXTreeID) {
- AXAuraObjCache::GetInstance()->FireEvent(
- this, ax::mojom::Event::kChildrenChanged);
+ aura_obj_cache_->FireEvent(this, ax::mojom::Event::kChildrenChanged);
}
}
void AXWindowObjWrapper::OnWindowVisibilityChanged(aura::Window* window,
bool visible) {
- AXAuraObjCache::GetInstance()->FireEvent(this,
- ax::mojom::Event::kStateChanged);
+ aura_obj_cache_->FireEvent(this, ax::mojom::Event::kStateChanged);
}
void AXWindowObjWrapper::OnWindowTransformed(aura::Window* window,
@@ -174,4 +179,24 @@ void AXWindowObjWrapper::OnWindowTitleChanged(aura::Window* window) {
FireEvent(window, ax::mojom::Event::kTextChanged);
}
+void AXWindowObjWrapper::FireEvent(aura::Window* window,
+ ax::mojom::Event event_type) {
+ aura_obj_cache_->FireEvent(aura_obj_cache_->GetOrCreate(window), event_type);
+
+ Widget* widget = GetWidgetForWindow(window);
+ if (widget) {
+ aura_obj_cache_->FireEvent(aura_obj_cache_->GetOrCreate(widget),
+ event_type);
+
+ views::View* root_view = widget->GetRootView();
+ if (root_view)
+ root_view->NotifyAccessibilityEvent(event_type, true);
+ }
+
+ aura::Window::Windows children =
+ AXAuraWindowUtils::Get()->GetChildren(window);
+ for (size_t i = 0; i < children.size(); ++i)
+ FireEvent(children[i], ax::mojom::Event::kLocationChanged);
+}
+
} // 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 de813581891..31d8525bce0 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "base/macros.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/aura/window_observer.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
@@ -17,20 +18,16 @@ class Window;
} // namespace aura
namespace views {
+class AXAuraObjCache;
// Describes a |Window| for use with other AX classes.
class AXWindowObjWrapper : public AXAuraObjWrapper,
public aura::WindowObserver {
public:
- explicit AXWindowObjWrapper(aura::Window* window);
+ // |aura_obj_cache| and |window| must outlive this object.
+ AXWindowObjWrapper(AXAuraObjCache* aura_obj_cache, aura::Window* window);
~AXWindowObjWrapper() override;
- // Whether this window is an alert window.
- bool is_alert() { return is_alert_; }
-
- // Sets whether this window is an alert window.
- void set_is_alert(bool is_alert) { is_alert_ = is_alert; }
-
// AXAuraObjWrapper overrides.
bool IsIgnored() override;
AXAuraObjWrapper* GetParent() override;
@@ -55,9 +52,13 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
void OnWindowTitleChanged(aura::Window* window) override;
private:
- aura::Window* window_;
+ // Fires 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);
- bool is_alert_;
+ AXAuraObjCache* const aura_obj_cache_;
+
+ aura::Window* window_;
bool is_root_window_;
diff --git a/chromium/ui/views/accessibility/view_accessibility.cc b/chromium/ui/views/accessibility/view_accessibility.cc
index 226bda50ed8..e1281a9c7fc 100644
--- a/chromium/ui/views/accessibility/view_accessibility.cc
+++ b/chromium/ui/views/accessibility/view_accessibility.cc
@@ -10,7 +10,7 @@
#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"
+#include "ui/base/buildflags.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -90,6 +90,7 @@ std::unique_ptr<AXVirtualView> ViewAccessibility::RemoveVirtualChildView(
std::move(virtual_children_[cur_index]);
virtual_children_.erase(virtual_children_.begin() + cur_index);
child->set_parent_view(nullptr);
+ child->UnsetPopulateDataCallback();
if (focused_virtual_child_ && child->Contains(focused_virtual_child_))
focused_virtual_child_ = nullptr;
return child;
@@ -167,6 +168,9 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
}
data->relative_bounds.bounds = gfx::RectF(view_->GetBoundsInScreen());
+ if (!custom_data_.relative_bounds.bounds.IsEmpty())
+ data->relative_bounds.bounds = custom_data_.relative_bounds.bounds;
+
data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
view_->GetClassName());
@@ -218,6 +222,10 @@ void ViewAccessibility::OverrideIsIgnored(bool value) {
is_ignored_ = value;
}
+void ViewAccessibility::OverrideBounds(const gfx::RectF& bounds) {
+ custom_data_.relative_bounds.bounds = bounds;
+}
+
gfx::NativeViewAccessible ViewAccessibility::GetNativeObject() {
return nullptr;
}
diff --git a/chromium/ui/views/accessibility/view_accessibility.h b/chromium/ui/views/accessibility/view_accessibility.h
index 43bc3434e54..26da24fa8f4 100644
--- a/chromium/ui/views/accessibility/view_accessibility.h
+++ b/chromium/ui/views/accessibility/view_accessibility.h
@@ -63,6 +63,7 @@ class VIEWS_EXPORT ViewAccessibility {
void OverrideDescription(const base::string16& description);
void OverrideIsLeaf(bool value);
void OverrideIsIgnored(bool value);
+ void OverrideBounds(const gfx::RectF& bounds);
virtual gfx::NativeViewAccessible GetNativeObject();
virtual void NotifyAccessibilityEvent(ax::mojom::Event event_type) {}
@@ -100,6 +101,11 @@ class VIEWS_EXPORT ViewAccessibility {
return static_cast<int>(virtual_children_.size());
}
+ AXVirtualView* virtual_child_at(int index) {
+ return const_cast<AXVirtualView*>(
+ const_cast<const ViewAccessibility*>(this)->virtual_child_at(index));
+ }
+
const AXVirtualView* virtual_child_at(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, virtual_child_count());
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 e0629603c9b..19527726665 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -13,6 +13,7 @@
#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_platform_node_base.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/events/event_utils.h"
#include "ui/views/accessibility/view_accessibility_utils.h"
@@ -25,9 +26,6 @@ namespace views {
namespace {
-base::LazyInstance<std::map<int32_t, ui::AXPlatformNode*>>::Leaky
- g_unique_id_to_ax_platform_node = LAZY_INSTANCE_INITIALIZER;
-
// Information required to fire a delayed accessibility event.
struct QueuedEvent {
QueuedEvent(ax::mojom::Event type, int32_t node_id)
@@ -82,12 +80,7 @@ ui::AXPlatformNode* FromNativeWindow(gfx::NativeWindow native_window) {
ui::AXPlatformNode* PlatformNodeFromNodeID(int32_t id) {
// Note: For Views, node IDs and unique IDs are the same - but that isn't
// necessarily true for all AXPlatformNodes.
- auto it = g_unique_id_to_ax_platform_node.Get().find(id);
-
- if (it == g_unique_id_to_ax_platform_node.Get().end())
- return nullptr;
-
- return it->second;
+ return ui::AXPlatformNodeBase::GetFromUniqueId(id);
}
void FireEvent(QueuedEvent event) {
@@ -120,16 +113,11 @@ ViewAXPlatformNodeDelegate::ViewAXPlatformNodeDelegate(View* view)
base::BindRepeating(&FromNativeWindow));
first_time = false;
}
-
- g_unique_id_to_ax_platform_node.Get()[GetUniqueId().Get()] =
- ax_platform_node_;
}
ViewAXPlatformNodeDelegate::~ViewAXPlatformNodeDelegate() {
if (ui::AXPlatformNode::GetPopupFocusOverride() == GetNativeObject())
ui::AXPlatformNode::SetPopupFocusOverride(nullptr);
-
- g_unique_id_to_ax_platform_node.Get().erase(GetUniqueId().Get());
ax_platform_node_->Destroy();
}
diff --git a/chromium/ui/views/accessible_pane_view.h b/chromium/ui/views/accessible_pane_view.h
index 6075569dd75..e67d90618ac 100644
--- a/chromium/ui/views/accessible_pane_view.h
+++ b/chromium/ui/views/accessible_pane_view.h
@@ -7,7 +7,6 @@
#include <memory>
-#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "ui/base/accelerators/accelerator.h"
diff --git a/chromium/ui/views/accessible_pane_view_unittest.cc b/chromium/ui/views/accessible_pane_view_unittest.cc
index f8e88ebfb46..e0bc5ea6119 100644
--- a/chromium/ui/views/accessible_pane_view_unittest.cc
+++ b/chromium/ui/views/accessible_pane_view_unittest.cc
@@ -137,19 +137,17 @@ TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore) {
EXPECT_EQ(test_view_bar->child_button(),
test_view_bar->GetWidget()->GetFocusManager()->GetFocusedView());
- if (!IsMus()) {
- // Deactivate() is only reliable on Ash. On Windows it uses
- // ::GetNextWindow() to simply activate another window, and which one is not
- // predictable. On Mac, Deactivate() is not implemented. Note that
- // TestBarView calls set_allow_deactivate_on_esc(true), which is only
- // otherwise used in Ash.
+ // Deactivate() is only reliable on Ash. On Windows it uses
+ // ::GetNextWindow() to simply activate another window, and which one is not
+ // predictable. On Mac, Deactivate() is not implemented. Note that
+ // TestBarView calls set_allow_deactivate_on_esc(true), which is only
+ // otherwise used in Ash.
#if !defined(OS_MACOSX) || defined(OS_CHROMEOS)
- // Esc should deactivate the widget.
- test_view_bar->AcceleratorPressed(test_view_bar->escape_key());
- EXPECT_TRUE(widget_main->IsActive());
- EXPECT_FALSE(widget_bar->IsActive());
+ // Esc should deactivate the widget.
+ test_view_bar->AcceleratorPressed(test_view_bar->escape_key());
+ EXPECT_TRUE(widget_main->IsActive());
+ EXPECT_FALSE(widget_bar->IsActive());
#endif
- }
widget_bar->CloseNow();
widget_bar.reset();
diff --git a/chromium/ui/views/animation/bounds_animator.cc b/chromium/ui/views/animation/bounds_animator.cc
index fc4e04c1854..b4bf7dbdbb1 100644
--- a/chromium/ui/views/animation/bounds_animator.cc
+++ b/chromium/ui/views/animation/bounds_animator.cc
@@ -29,7 +29,10 @@ BoundsAnimator::~BoundsAnimator() {
CleanupData(false, &entry.second);
}
-void BoundsAnimator::AnimateViewTo(View* view, const gfx::Rect& target) {
+void BoundsAnimator::AnimateViewTo(
+ View* view,
+ const gfx::Rect& target,
+ std::unique_ptr<gfx::AnimationDelegate> delegate) {
DCHECK(view);
DCHECK_EQ(view->parent(), parent_);
@@ -50,6 +53,7 @@ void BoundsAnimator::AnimateViewTo(View* view, const gfx::Rect& target) {
data.start_bounds = view->bounds();
data.target_bounds = target;
data.animation = CreateAnimation();
+ data.delegate = std::move(delegate);
animation_to_view_[data.animation.get()] = view;
diff --git a/chromium/ui/views/animation/bounds_animator.h b/chromium/ui/views/animation/bounds_animator.h
index e72714fefb3..7524edb695b 100644
--- a/chromium/ui/views/animation/bounds_animator.h
+++ b/chromium/ui/views/animation/bounds_animator.h
@@ -47,7 +47,10 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate,
// already an animation running for the view it's stopped and a new one
// started. If an AnimationDelegate has been set for |view| it is removed
// (after being notified that the animation was canceled).
- void AnimateViewTo(View* view, const gfx::Rect& target);
+ void AnimateViewTo(
+ View* view,
+ const gfx::Rect& target,
+ std::unique_ptr<gfx::AnimationDelegate> delegate = nullptr);
// Similar to |AnimateViewTo|, but does not reset the animation, only the
// target bounds. If |view| is not being animated this is the same as
diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc
index 9b8181553ae..bb0f1793d4a 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view.cc
@@ -16,6 +16,7 @@
#include "ui/views/animation/ink_drop_mask.h"
#include "ui/views/animation/ink_drop_stub.h"
#include "ui/views/animation/square_ink_drop_ripple.h"
+#include "ui/views/controls/focus_ring.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/view_properties.h"
@@ -146,36 +147,32 @@ void InkDropHostView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
}
std::unique_ptr<InkDrop> InkDropHostView::CreateInkDrop() {
- return CreateDefaultInkDropImpl();
+ return CreateDefaultFloodFillInkDropImpl();
}
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());
+ return std::make_unique<views::FloodFillInkDropRipple>(
+ size(), gfx::Insets(), GetInkDropCenterBasedOnLastEvent(),
+ GetInkDropBaseColor(), ink_drop_visible_opacity());
}
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());
+ auto highlight = std::make_unique<views::InkDropHighlight>(
+ size(), 0, gfx::RectF(GetMirroredRect(GetLocalBounds())).CenterPoint(),
+ GetInkDropBaseColor());
+ // TODO(pbos): Once |ink_drop_highlight_opacity_| is either always set or
+ // callers are using the default InkDropHighlight value then make this a
+ // constructor argument to InkDropHighlight.
+ if (ink_drop_highlight_opacity_)
+ highlight->set_visible_opacity(*ink_drop_highlight_opacity_);
+
+ return highlight;
}
std::unique_ptr<views::InkDropMask> InkDropHostView::CreateInkDropMask() const {
- if (SkPath* highlight_path = GetProperty(kHighlightPathKey))
- return std::make_unique<views::PathInkDropMask>(size(), *highlight_path);
-
- return nullptr;
+ return std::make_unique<views::PathInkDropMask>(size(),
+ GetHighlightPath(this));
}
SkColor InkDropHostView::GetInkDropBaseColor() const {
@@ -249,7 +246,7 @@ std::unique_ptr<InkDropImpl> InkDropHostView::CreateDefaultInkDropImpl() {
std::unique_ptr<InkDropImpl>
InkDropHostView::CreateDefaultFloodFillInkDropImpl() {
- std::unique_ptr<views::InkDropImpl> ink_drop = CreateDefaultInkDropImpl();
+ auto ink_drop = std::make_unique<InkDropImpl>(this, size());
ink_drop->SetAutoHighlightMode(
views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE);
return ink_drop;
@@ -258,6 +255,12 @@ InkDropHostView::CreateDefaultFloodFillInkDropImpl() {
std::unique_ptr<InkDropRipple> InkDropHostView::CreateDefaultInkDropRipple(
const gfx::Point& center_point,
const gfx::Size& size) const {
+ return CreateSquareInkDropRipple(center_point, size);
+}
+
+std::unique_ptr<InkDropRipple> InkDropHostView::CreateSquareInkDropRipple(
+ 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(),
@@ -268,6 +271,12 @@ std::unique_ptr<InkDropRipple> InkDropHostView::CreateDefaultInkDropRipple(
std::unique_ptr<InkDropHighlight>
InkDropHostView::CreateDefaultInkDropHighlight(const gfx::PointF& center_point,
const gfx::Size& size) const {
+ return CreateSquareInkDropHighlight(center_point, size);
+}
+
+std::unique_ptr<InkDropHighlight> InkDropHostView::CreateSquareInkDropHighlight(
+ 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)));
diff --git a/chromium/ui/views/animation/ink_drop_host_view.h b/chromium/ui/views/animation/ink_drop_host_view.h
index f374839b019..b137d7ff80e 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.h
+++ b/chromium/ui/views/animation/ink_drop_host_view.h
@@ -95,6 +95,10 @@ class VIEWS_EXPORT InkDropHostView : public View {
}
float ink_drop_visible_opacity() const { return ink_drop_visible_opacity_; }
+ void set_ink_drop_highlight_opacity(base::Optional<float> opacity) {
+ ink_drop_highlight_opacity_ = opacity;
+ }
+
void set_ink_drop_corner_radii(int small_radius, int large_radius) {
ink_drop_small_corner_radius_ = small_radius;
ink_drop_large_corner_radius_ = large_radius;
@@ -130,26 +134,38 @@ class VIEWS_EXPORT InkDropHostView : public View {
void OnFocus() override;
void OnBlur() override;
- // Returns an InkDropImpl with default configuration. The base implementation
- // of CreateInkDrop() delegates to this function.
+ // Returns an InkDropImpl suitable for use with a square ink drop.
+ // TODO(pbos): Rename to CreateDefaultSquareInkDropImpl.
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|.
+ // TODO(pbos): Migrate uses to CreateSquareInkDropRipple which this calls
+ // directly.
std::unique_ptr<InkDropRipple> CreateDefaultInkDropRipple(
const gfx::Point& center_point,
const gfx::Size& size = gfx::Size(kDefaultInkDropSize,
kDefaultInkDropSize)) const;
- // Returns the default InkDropHighlight centered on |center_point|.
+ // Creates a SquareInkDropRipple centered on |center_point|.
+ std::unique_ptr<InkDropRipple> CreateSquareInkDropRipple(
+ const gfx::Point& center_point,
+ const gfx::Size& size) const;
+
+ // TODO(pbos): Migrate uses to CreateSquareInkDropHighlight which this calls
+ // directly.
std::unique_ptr<InkDropHighlight> CreateDefaultInkDropHighlight(
const gfx::PointF& center_point,
const gfx::Size& size = gfx::Size(kDefaultInkDropSize,
kDefaultInkDropSize)) const;
+ // Creates a InkDropHighlight centered on |center_point|.
+ std::unique_ptr<InkDropHighlight> CreateSquareInkDropHighlight(
+ const gfx::PointF& center_point,
+ const gfx::Size& size) const;
+
// Returns true if an ink drop instance has been created.
bool HasInkDrop() const;
@@ -191,6 +207,10 @@ class VIEWS_EXPORT InkDropHostView : public View {
float ink_drop_visible_opacity_ = 0.175f;
+ // TODO(pbos): Audit call sites to make sure highlight opacity is either
+ // always set or using the default value. Then make this a non-optional float.
+ base::Optional<float> ink_drop_highlight_opacity_;
+
// Radii used for the SquareInkDropRipple.
int ink_drop_small_corner_radius_ = 2;
int ink_drop_large_corner_radius_ = 4;
@@ -208,4 +228,4 @@ class VIEWS_EXPORT InkDropHostView : public View {
} // namespace views
-#endif // UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_ \ No newline at end of file
+#endif // UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_
diff --git a/chromium/ui/views/animation/ink_drop_impl.cc b/chromium/ui/views/animation/ink_drop_impl.cc
index a28b1b82e7f..11e143c1701 100644
--- a/chromium/ui/views/animation/ink_drop_impl.cc
+++ b/chromium/ui/views/animation/ink_drop_impl.cc
@@ -621,10 +621,6 @@ void InkDropImpl::SetAutoHighlightMode(AutoHighlightMode auto_highlight_mode) {
SetHighlightState(highlight_state_factory_->CreateStartState());
}
-void InkDropImpl::SetAutoHighlightModeForPlatform() {
- SetAutoHighlightMode(AutoHighlightMode::HIDE_ON_RIPPLE);
-}
-
void InkDropImpl::HostSizeChanged(const gfx::Size& new_size) {
// |root_layer_| should fill the entire host because it affects the clipping
// when a mask layer is applied to it. This will not affect clipping if no
diff --git a/chromium/ui/views/animation/ink_drop_impl.h b/chromium/ui/views/animation/ink_drop_impl.h
index 82061d7e778..1c1d8892a91 100644
--- a/chromium/ui/views/animation/ink_drop_impl.h
+++ b/chromium/ui/views/animation/ink_drop_impl.h
@@ -60,13 +60,10 @@ class VIEWS_EXPORT InkDropImpl : public InkDrop,
// This method is intended as a configuration option to be used after
// construction. Behavior is undefined if |this| has already handled any
// InkDrop inherited functions.
+ // TODO(pbos): Move along with AutoHighlightMode to views::InkDrop so users
+ // can configure inkdrops created by parent classes.
void SetAutoHighlightMode(AutoHighlightMode auto_highlight_mode);
- // Sets the AutoHighlightMode as per the platform. Platforms that show ripples
- // will be set to HIDE_ON_RIPPLE, and platforms that don't show ripples are
- // set to SHOW_ON_RIPPLE highlight behavior.
- void SetAutoHighlightModeForPlatform();
-
const base::Optional<int>& hover_highlight_fade_duration_ms() const {
return hover_highlight_fade_duration_ms_;
}
diff --git a/chromium/ui/views/animation/ink_drop_impl_unittest.cc b/chromium/ui/views/animation/ink_drop_impl_unittest.cc
index d5d6ecf641d..dbe46ff285c 100644
--- a/chromium/ui/views/animation/ink_drop_impl_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_impl_unittest.cc
@@ -252,13 +252,6 @@ TEST_F(InkDropImplTest, LayersArentRemovedWhenPreemptingFadeOut) {
TEST_F(InkDropImplTest,
SettingHighlightStateDuringStateExitIsntAllowedDeathTest) {
- // gtest death tests, such as EXPECT_DCHECK_DEATH(), can not work in the
- // presence of fork() and other process launching. In views-mus, we have
- // already launched additional processes for our service manager. Performing
- // this test under mus is impossible.
- if (PlatformTestHelper::IsMus())
- return;
-
::testing::FLAGS_gtest_death_test_style = "threadsafe";
test::InkDropImplTestApi::SetStateOnExitHighlightState::Install(
diff --git a/chromium/ui/views/animation/ink_drop_mask.h b/chromium/ui/views/animation/ink_drop_mask.h
index 8631269a403..5254f656c65 100644
--- a/chromium/ui/views/animation/ink_drop_mask.h
+++ b/chromium/ui/views/animation/ink_drop_mask.h
@@ -11,9 +11,10 @@
#include "ui/gfx/geometry/insets_f.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/path.h"
#include "ui/views/views_export.h"
+class SkPath;
+
namespace views {
// Base class for different ink drop masks. It is responsible for creating the
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 cffabb85ff9..eb57c1be2a3 100644
--- a/chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc
+++ b/chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/point.h"
@@ -159,7 +159,7 @@ TEST_F(SquareInkDropRippleCalculateTransformsTest,
gfx::Point(0, 0), gfx::Point(0, -kHalfTransformedSize),
gfx::Point(0, kHalfTransformedSize)}};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
PaintedShape shape = test_cases[i].shape;
SCOPED_TRACE(testing::Message() << "i=" << i << " shape=" << shape);
gfx::Transform transform = transforms_[shape];
@@ -222,7 +222,7 @@ TEST_F(SquareInkDropRippleCalculateTransformsTest,
gfx::Point(x_offset, 0), gfx::Point(0, -kHalfTransformedSize),
gfx::Point(0, kHalfTransformedSize)}};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
PaintedShape shape = test_cases[i].shape;
SCOPED_TRACE(testing::Message() << "i=" << i << " shape=" << shape);
gfx::Transform transform = transforms_[shape];
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index 60d6ed5ac06..dd0c1d07b54 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -15,7 +15,6 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/shadow_value.h"
#include "ui/gfx/skia_paint_util.h"
@@ -90,46 +89,85 @@ void BubbleBorder::SetCornerRadius(int corner_radius) {
gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
const gfx::Size& contents_size) const {
// In MD, there are no arrows, so positioning logic is significantly simpler.
- // TODO(estade): handle more anchor positions.
- if (arrow_ == TOP_RIGHT || arrow_ == TOP_LEFT || arrow_ == BOTTOM_CENTER ||
- arrow_ == TOP_CENTER || arrow_ == LEFT_CENTER || arrow_ == RIGHT_CENTER) {
+ if (has_arrow(arrow_)) {
gfx::Rect contents_bounds(contents_size);
- // Apply the border part of the inset before calculating coordinates because
- // the border should align with the anchor's border. For the purposes of
- // positioning, the border is rounded up to a dip, which may mean we have
- // misalignment in scale factors greater than 1. Borders with custom shadow
- // elevations do not draw the 1px border.
+ // Always apply the border part of the inset before calculating coordinates,
+ // that ensures the bubble's border is aligned with the anchor's border.
+ // For the purposes of positioning, the border is rounded up to a dip, which
+ // may cause misalignment in scale factors greater than 1.
// TODO(estade): when it becomes possible to provide px bounds instead of
// dip bounds, fix this.
+ // Borders with custom shadow elevations do not draw the 1px border.
const gfx::Insets border_insets =
shadow_ == NO_ASSETS || md_shadow_elevation_.has_value()
? gfx::Insets()
: gfx::Insets(kBorderThicknessDip);
const gfx::Insets shadow_insets = GetInsets() - border_insets;
contents_bounds.Inset(-border_insets);
- if (arrow_ == TOP_RIGHT) {
- contents_bounds +=
- anchor_rect.bottom_right() - contents_bounds.top_right();
- } else if (arrow_ == TOP_LEFT) {
- contents_bounds +=
- anchor_rect.bottom_left() - contents_bounds.origin();
- } else if (arrow_ == BOTTOM_CENTER) {
- contents_bounds += CenterTop(anchor_rect) - CenterBottom(contents_bounds);
- } else if (arrow_ == TOP_CENTER) {
- contents_bounds += CenterBottom(anchor_rect) - CenterTop(contents_bounds);
- } else if (arrow_ == LEFT_CENTER) {
- contents_bounds += RightCenter(anchor_rect) - LeftCenter(contents_bounds);
- } else if (arrow_ == RIGHT_CENTER) {
- contents_bounds += LeftCenter(anchor_rect) - RightCenter(contents_bounds);
+ // If |avoid_shadow_overlap_| is true, the shadow part of the inset is also
+ // applied now, to ensure that the shadow itself doesn't overlap the anchor.
+ if (avoid_shadow_overlap_)
+ contents_bounds.Inset(-shadow_insets);
+ switch (arrow_) {
+ case TOP_LEFT:
+ contents_bounds += anchor_rect.bottom_left() - contents_bounds.origin();
+ break;
+ case TOP_RIGHT:
+ contents_bounds +=
+ anchor_rect.bottom_right() - contents_bounds.top_right();
+ break;
+ case BOTTOM_LEFT:
+ contents_bounds += anchor_rect.origin() - contents_bounds.bottom_left();
+ break;
+ case BOTTOM_RIGHT:
+ contents_bounds +=
+ anchor_rect.top_right() - contents_bounds.bottom_right();
+ break;
+ case LEFT_TOP:
+ contents_bounds += anchor_rect.top_right() - contents_bounds.origin();
+ break;
+ case RIGHT_TOP:
+ contents_bounds += anchor_rect.origin() - contents_bounds.top_right();
+ break;
+ case LEFT_BOTTOM:
+ contents_bounds +=
+ anchor_rect.bottom_right() - contents_bounds.bottom_left();
+ break;
+ case RIGHT_BOTTOM:
+ contents_bounds +=
+ anchor_rect.bottom_left() - contents_bounds.bottom_right();
+ break;
+ case TOP_CENTER:
+ contents_bounds +=
+ CenterBottom(anchor_rect) - CenterTop(contents_bounds);
+ break;
+ case BOTTOM_CENTER:
+ contents_bounds +=
+ CenterTop(anchor_rect) - CenterBottom(contents_bounds);
+ break;
+ case LEFT_CENTER:
+ contents_bounds +=
+ RightCenter(anchor_rect) - LeftCenter(contents_bounds);
+ break;
+ case RIGHT_CENTER:
+ contents_bounds +=
+ LeftCenter(anchor_rect) - RightCenter(contents_bounds);
+ break;
+ default:
+ NOTREACHED();
}
// With NO_ASSETS, there should be further insets, but the same logic is
// used to position the bubble origin according to |anchor_rect|.
DCHECK((shadow_ != NO_ASSETS && shadow_ != NO_SHADOW) ||
shadow_insets.IsEmpty());
- contents_bounds.Inset(-shadow_insets);
+ if (!avoid_shadow_overlap_)
+ contents_bounds.Inset(-shadow_insets);
// |arrow_offset_| is used to adjust bubbles that would normally be
// partially offscreen.
- contents_bounds += gfx::Vector2d(-arrow_offset_, 0);
+ if (is_arrow_on_horizontal(arrow_))
+ contents_bounds += gfx::Vector2d(-arrow_offset_, 0);
+ else
+ contents_bounds += gfx::Vector2d(0, -arrow_offset_);
return contents_bounds;
}
@@ -305,7 +343,6 @@ void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
flags.setAntiAlias(true);
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setColor(border_->background_color());
- SkPath path;
gfx::RectF bounds(view->GetLocalBounds());
bounds.Inset(gfx::InsetsF(border_->GetInsets()));
diff --git a/chromium/ui/views/bubble/bubble_border.h b/chromium/ui/views/bubble/bubble_border.h
index 79c182cffd1..007361a7bbf 100644
--- a/chromium/ui/views/bubble/bubble_border.h
+++ b/chromium/ui/views/bubble/bubble_border.h
@@ -182,6 +182,9 @@ class VIEWS_EXPORT BubbleBorder : public Border {
md_shadow_color_ = shadow_color;
}
+ // Set a flag to avoid the bubble's shadow overlapping the anchor.
+ void set_avoid_shadow_overlap(bool value) { avoid_shadow_overlap_ = value; }
+
// Get the desired widget bounds (in screen coordinates) given the anchor rect
// and bubble content size; calculated from shadow and arrow image dimensions.
virtual gfx::Rect GetBounds(const gfx::Rect& anchor_rect,
@@ -245,6 +248,7 @@ class VIEWS_EXPORT BubbleBorder : public Border {
SkColor md_shadow_color_ = SK_ColorBLACK;
SkColor background_color_;
bool use_theme_background_color_;
+ bool avoid_shadow_overlap_ = false;
DISALLOW_COPY_AND_ASSIGN(BubbleBorder);
};
diff --git a/chromium/ui/views/bubble/bubble_border_unittest.cc b/chromium/ui/views/bubble/bubble_border_unittest.cc
index f4f1c908206..77fdae7a424 100644
--- a/chromium/ui/views/bubble/bubble_border_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_border_unittest.cc
@@ -8,7 +8,7 @@
#include <memory>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h"
@@ -281,7 +281,7 @@ TEST_F(BubbleBorderTest, GetSizeForContentsSizeTest) {
{BubbleBorder::NONE, kMediumSize, kMediumNoArrow},
{BubbleBorder::FLOAT, kMediumSize, kMediumNoArrow}};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
SCOPED_TRACE(base::StringPrintf("i=%d arrow=%d",
static_cast<int>(i), cases[i].arrow));
@@ -316,10 +316,18 @@ TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
const int kBorderedContentHeight =
kContentSize.height() + (2 * kStrokeWidth);
- const int kTopHorizArrowY = kAnchor.bottom() + kStrokeWidth - kInsets.top();
- const int kBottomHorizArrowY = kAnchor.y() - kTotalSize.height();
- const int kLeftVertArrowX = kAnchor.x() + kAnchor.width();
- const int kRightVertArrowX = kAnchor.x() - kTotalSize.width();
+ const int kStrokeTopInset = kStrokeWidth - kInsets.top();
+ const int kStrokeBottomInset = kStrokeWidth - kInsets.bottom();
+ const int kStrokeLeftInset = kStrokeWidth - kInsets.left();
+ const int kStrokeRightInset = kStrokeWidth - kInsets.right();
+
+ const int kTopHorizArrowY = kAnchor.bottom() + kStrokeTopInset;
+ const int kBottomHorizArrowY =
+ kAnchor.y() - kTotalSize.height() - kStrokeBottomInset;
+ const int kLeftVertArrowX =
+ kAnchor.x() + kAnchor.width() + kStrokeLeftInset;
+ const int kRightVertArrowX =
+ kAnchor.x() - kTotalSize.width() - kStrokeRightInset;
struct TestCase {
BubbleBorder::Arrow arrow;
@@ -329,22 +337,23 @@ TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
TestCase cases[] = {
// Horizontal arrow tests.
- {BubbleBorder::TOP_LEFT, kAnchor.x() + kStrokeWidth - kInsets.left(),
+ {BubbleBorder::TOP_LEFT, kAnchor.x() + kStrokeLeftInset,
kTopHorizArrowY},
{BubbleBorder::TOP_CENTER,
kAnchor.CenterPoint().x() - (kTotalSize.width() / 2), kTopHorizArrowY},
{BubbleBorder::BOTTOM_RIGHT,
- kAnchor.x() + kAnchor.width() - kTotalSize.width() - kStrokeWidth,
+ kAnchor.x() + kAnchor.width() - kTotalSize.width() - kStrokeRightInset,
kBottomHorizArrowY},
// Vertical arrow tests.
- {BubbleBorder::LEFT_TOP, kLeftVertArrowX, kAnchor.y() + kStrokeWidth},
- {BubbleBorder::LEFT_CENTER,
- kLeftVertArrowX - (kInsets.left() - kStrokeWidth),
- kAnchor.CenterPoint().y() - (kBorderedContentHeight / 2) -
- (kInsets.top() - kStrokeWidth)},
+ {BubbleBorder::LEFT_TOP, kLeftVertArrowX,
+ kAnchor.y() + kStrokeTopInset},
+ {BubbleBorder::LEFT_CENTER, kLeftVertArrowX,
+ kAnchor.CenterPoint().y() - (kBorderedContentHeight / 2) +
+ kStrokeTopInset},
{BubbleBorder::RIGHT_BOTTOM, kRightVertArrowX,
- kAnchor.y() + kAnchor.height() - kTotalSize.height() - kStrokeWidth},
+ kAnchor.y() + kAnchor.height() - kTotalSize.height() -
+ kStrokeBottomInset},
// No arrow tests.
{BubbleBorder::NONE,
@@ -355,7 +364,7 @@ TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
kAnchor.y() + (kAnchor.height() - kTotalSize.height()) / 2},
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
SCOPED_TRACE(base::StringPrintf("shadow=%d i=%d arrow=%d",
static_cast<int>(shadow),
static_cast<int>(i), cases[i].arrow));
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
index 447cab79b78..e7303be1b5c 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -162,6 +162,16 @@ const char* BubbleDialogDelegateView::GetClassName() const {
return kViewClassName;
}
+void BubbleDialogDelegateView::OnWidgetClosing(Widget* widget) {
+ // To prevent keyboard focus traversal issues, the anchor view's
+ // kAnchoredDialogKey property is cleared immediately upon Close(). This
+ // avoids a bug that occured when a focused anchor view is made unfocusable
+ // right after the bubble is closed. Previously, focus would advance into the
+ // bubble then would be lost when the bubble was destroyed.
+ if (widget == GetWidget() && GetAnchorView())
+ GetAnchorView()->ClearProperty(kAnchoredDialogKey);
+}
+
void BubbleDialogDelegateView::OnWidgetDestroying(Widget* widget) {
if (anchor_widget() == widget)
SetAnchorView(NULL);
@@ -433,7 +443,7 @@ void BubbleDialogDelegateView::HandleVisibilityChanged(Widget* widget,
void BubbleDialogDelegateView::OnDeactivate() {
if (close_on_deactivate() && GetWidget())
- GetWidget()->Close();
+ GetWidget()->CloseWithReason(views::Widget::ClosedReason::kLostFocus);
}
void BubbleDialogDelegateView::UpdateAnchorWidgetRenderState(bool visible) {
@@ -446,7 +456,7 @@ void BubbleDialogDelegateView::UpdateAnchorWidgetRenderState(bool visible) {
void BubbleDialogDelegateView::UpdateHighlightedButton(bool highlighted) {
Button* button = Button::AsButton(highlighted_button_tracker_.view());
button = button ? button : Button::AsButton(anchor_view_tracker_->view());
- if (button)
+ if (button && highlight_button_when_shown_)
button->SetHighlighted(highlighted);
}
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
index a5b2d11c96b..d154773439e 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -56,6 +56,7 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
const char* GetClassName() const override;
// WidgetObserver:
+ void OnWidgetClosing(Widget* widget) override;
void OnWidgetDestroying(Widget* widget) override;
void OnWidgetVisibilityChanging(Widget* widget, bool visible) override;
void OnWidgetVisibilityChanged(Widget* widget, bool visible) override;
@@ -104,6 +105,10 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
bool adjust_if_offscreen() const { return adjust_if_offscreen_; }
void set_adjust_if_offscreen(bool adjust) { adjust_if_offscreen_ = adjust; }
+ void set_highlight_button_when_shown(bool highlight) {
+ highlight_button_when_shown_ = highlight;
+ }
+
// Get the arrow's anchor rect in screen space.
virtual gfx::Rect GetAnchorRect() const;
@@ -192,6 +197,10 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
std::unique_ptr<ViewTracker> anchor_view_tracker_;
Widget* anchor_widget_;
+ // Whether the |anchor_widget_| (or the |highlighted_button_tracker_|, when
+ // provided) should be highlighted when this bubble is shown.
+ bool highlight_button_when_shown_ = true;
+
// If provided, this button should be highlighted while the bubble is visible.
// If not provided, the anchor_view will attempt to be highlighted. A
// ViewTracker is used because the view can be deleted.
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 dd72bf4f8e6..5b2313f9ebd 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -7,7 +7,7 @@
#include <stddef.h>
#include "base/i18n/rtl.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/hit_test.h"
#include "ui/events/event_utils.h"
@@ -279,7 +279,7 @@ TEST_F(BubbleDialogDelegateViewTest, NonClientHitTest) {
{0, HTNOWHERE}, {60, HTCLIENT}, {1000, HTNOWHERE},
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
gfx::Point point(cases[i].point, cases[i].point);
EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
<< " at point " << cases[i].point;
diff --git a/chromium/ui/views/bubble/bubble_frame_view.cc b/chromium/ui/views/bubble/bubble_frame_view.cc
index b8142736255..b07b413f332 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view.cc
@@ -9,6 +9,7 @@
#include "build/build_config.h"
#include "components/vector_icons/vector_icons.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/default_style.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
@@ -18,7 +19,6 @@
#include "ui/display/screen.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/skia_util.h"
#include "ui/native_theme/native_theme.h"
#include "ui/resources/grit/ui_resources.h"
@@ -82,14 +82,13 @@ BubbleFrameView::BubbleFrameView(const gfx::Insets& title_margins,
default_title_(CreateDefaultTitleLabel(base::string16()).release()),
custom_title_(nullptr),
close_(nullptr),
- footnote_container_(nullptr),
- close_button_clicked_(false) {
+ footnote_container_(nullptr) {
AddChildView(title_icon_);
default_title_->SetVisible(false);
AddChildView(default_title_);
- close_ = CreateCloseButton(this);
+ close_ = CreateCloseButton(this, GetNativeTheme()->SystemDarkModeEnabled());
close_->SetVisible(false);
#if defined(OS_WIN)
// Windows will automatically create a tooltip for the close button based on
@@ -112,10 +111,13 @@ std::unique_ptr<Label> BubbleFrameView::CreateDefaultTitleLabel(
}
// static
-Button* BubbleFrameView::CreateCloseButton(ButtonListener* listener) {
+Button* BubbleFrameView::CreateCloseButton(ButtonListener* listener,
+ bool is_dark_mode) {
ImageButton* close_button = nullptr;
close_button = CreateVectorImageButton(listener);
- SetImageFromVectorIcon(close_button, vector_icons::kCloseRoundedIcon);
+ SetImageFromVectorIconWithColor(
+ close_button, vector_icons::kCloseRoundedIcon,
+ is_dark_mode ? SkColorSetA(SK_ColorWHITE, 0xDD) : gfx::kGoogleGrey700);
close_button->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_CLOSE));
close_button->SizeToPreferredSize();
@@ -152,22 +154,24 @@ gfx::Rect BubbleFrameView::GetWindowBoundsForClientBounds(
return bubble_border_->GetBounds(gfx::Rect(), size);
}
-bool BubbleFrameView::GetClientMask(const gfx::Size& size,
- gfx::Path* path) const {
+bool BubbleFrameView::GetClientMask(const gfx::Size& size, SkPath* path) const {
// NonClientView calls this after setting the client view size from the return
// of GetBoundsForClientView(); feeding it back in |size|.
DCHECK(GetBoundsForClientView().size() == size);
DCHECK(GetWidget()->client_view()->size() == size);
const int radius = bubble_border_->GetBorderCornerRadius();
- gfx::Insets content_insets = GetInsets();
- // If the client bounds don't touch the edges, no need to mask.
- if (std::min({content_insets.top(), content_insets.left(),
- content_insets.bottom(), content_insets.right()}) > radius) {
+ const gfx::Insets insets =
+ GetClientInsetsForFrameWidth(GetContentsBounds().width());
+
+ // A mask is not needed if the content does not overlap the rounded corners.
+ if ((insets.top() > radius && insets.bottom() > radius) ||
+ (insets.left() > radius && insets.right() > radius)) {
return false;
}
- gfx::RectF rect((gfx::Rect(size)));
- path->addRoundRect(gfx::RectFToSkRect(rect), radius, radius);
+
+ const SkRect rect = SkRect::MakeIWH(size.width(), size.height());
+ path->addRoundRect(rect, radius, radius);
return true;
}
@@ -194,7 +198,7 @@ int BubbleFrameView::NonClientHitTest(const gfx::Point& point) {
}
void BubbleFrameView::GetWindowMask(const gfx::Size& size,
- gfx::Path* window_mask) {
+ SkPath* window_mask) {
if (bubble_border_->shadow() != BubbleBorder::SMALL_SHADOW &&
bubble_border_->shadow() != BubbleBorder::NO_SHADOW_OPAQUE_BORDER &&
bubble_border_->shadow() != BubbleBorder::NO_ASSETS)
@@ -267,10 +271,6 @@ const char* BubbleFrameView::GetClassName() const {
return kViewClassName;
}
-gfx::Insets BubbleFrameView::GetInsets() const {
- return GetClientInsetsForFrameWidth(GetContentsBounds().width());
-}
-
gfx::Size BubbleFrameView::CalculatePreferredSize() const {
// Get the preferred size of the client area.
gfx::Size client_size = GetWidget()->client_view()->GetPreferredSize();
@@ -428,8 +428,7 @@ void BubbleFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
return;
if (sender == close_) {
- close_button_clicked_ = true;
- GetWidget()->Close();
+ GetWidget()->CloseWithReason(Widget::ClosedReason::kCloseButtonClicked);
}
}
diff --git a/chromium/ui/views/bubble/bubble_frame_view.h b/chromium/ui/views/bubble/bubble_frame_view.h
index 40175e1385c..ac8ebf65cf1 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.h
+++ b/chromium/ui/views/bubble/bubble_frame_view.h
@@ -5,6 +5,8 @@
#ifndef UI_VIEWS_BUBBLE_BUBBLE_FRAME_VIEW_H_
#define UI_VIEWS_BUBBLE_BUBBLE_FRAME_VIEW_H_
+#include <memory>
+
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
@@ -36,15 +38,15 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
const base::string16& title_text);
// Creates a close button used in the corner of the dialog.
- static Button* CreateCloseButton(ButtonListener* listener);
+ static Button* CreateCloseButton(ButtonListener* listener, bool is_dark_mode);
// NonClientFrameView:
gfx::Rect GetBoundsForClientView() const override;
gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const override;
- bool GetClientMask(const gfx::Size& size, gfx::Path* path) const override;
+ bool GetClientMask(const gfx::Size& size, SkPath* path) const override;
int NonClientHitTest(const gfx::Point& point) override;
- void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override;
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override;
void ResetWindowControls() override;
void UpdateWindowIcon() override;
void UpdateWindowTitle() override;
@@ -56,7 +58,6 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
// View:
const char* GetClassName() const override;
- gfx::Insets GetInsets() const override;
gfx::Size CalculatePreferredSize() const override;
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
@@ -98,8 +99,6 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
const gfx::Size& client_size,
bool adjust_if_offscreen);
- bool close_button_clicked() const { return close_button_clicked_; }
-
Button* GetCloseButtonForTest() { return close_; }
// Resets the time when view has been shown. Tests may need to call this
@@ -186,9 +185,6 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
// A view to contain the footnote view, if it exists.
FootnoteContainerView* footnote_container_;
- // Whether the close button was clicked.
- bool close_button_clicked_;
-
// Time when view has been shown.
base::TimeTicks view_shown_time_stamp_;
diff --git a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
index bd244a5bfc9..9db93c2c19a 100644
--- a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -132,11 +132,29 @@ TEST_F(BubbleFrameViewTest, GetBoundsForClientView) {
EXPECT_EQ(kArrow, frame.bubble_border()->arrow());
EXPECT_EQ(kColor, frame.bubble_border()->background_color());
- int margin_x = frame.content_margins().left();
- int margin_y = frame.content_margins().top();
- gfx::Insets insets = frame.bubble_border()->GetInsets();
- EXPECT_EQ(insets.left() + margin_x, frame.GetBoundsForClientView().x());
- EXPECT_EQ(insets.top() + margin_y, frame.GetBoundsForClientView().y());
+ const gfx::Insets content_margins = frame.content_margins();
+ const gfx::Insets insets = frame.GetInsets();
+ const gfx::Rect client_view_bounds = frame.GetBoundsForClientView();
+ EXPECT_EQ(insets.left() + content_margins.left(), client_view_bounds.x());
+ EXPECT_EQ(insets.top() + content_margins.top(), client_view_bounds.y());
+}
+
+TEST_F(BubbleFrameViewTest, GetBoundsForClientViewWithClose) {
+ TestBubbleFrameView frame(this);
+ frame.widget_delegate()->SetShouldShowCloseButton(true);
+ frame.ResetWindowControls();
+ EXPECT_EQ(kArrow, frame.bubble_border()->arrow());
+ EXPECT_EQ(kColor, frame.bubble_border()->background_color());
+
+ const gfx::Insets content_margins = frame.content_margins();
+ const gfx::Insets insets = frame.GetInsets();
+ const int close_margin =
+ frame.GetCloseButtonForTest()->height() +
+ LayoutProvider::Get()->GetDistanceMetric(DISTANCE_CLOSE_BUTTON_MARGIN);
+ const gfx::Rect client_view_bounds = frame.GetBoundsForClientView();
+ EXPECT_EQ(insets.left() + content_margins.left(), client_view_bounds.x());
+ EXPECT_EQ(insets.top() + content_margins.top() + close_margin,
+ client_view_bounds.y());
}
TEST_F(BubbleFrameViewTest, RemoveFootnoteView) {
@@ -152,21 +170,6 @@ TEST_F(BubbleFrameViewTest, RemoveFootnoteView) {
EXPECT_EQ(nullptr, frame.footnote_container_);
}
-TEST_F(BubbleFrameViewTest, GetBoundsForClientViewWithClose) {
- TestBubbleFrameView frame(this);
- frame.widget_delegate()->SetShouldShowCloseButton(true);
- frame.ResetWindowControls();
- EXPECT_EQ(kArrow, frame.bubble_border()->arrow());
- EXPECT_EQ(kColor, frame.bubble_border()->background_color());
-
- gfx::Insets frame_insets = frame.GetInsets();
- gfx::Insets border_insets = frame.bubble_border()->GetInsets();
- EXPECT_EQ(border_insets.left() + frame_insets.left(),
- frame.GetBoundsForClientView().x());
- EXPECT_EQ(border_insets.top() + frame_insets.top(),
- frame.GetBoundsForClientView().y());
-}
-
TEST_F(BubbleFrameViewTest,
FootnoteContainerViewShouldMatchVisibilityOfFirstChild) {
TestBubbleFrameView frame(this);
diff --git a/chromium/ui/views/bubble/footnote_container_view.cc b/chromium/ui/views/bubble/footnote_container_view.cc
index e8a28b3b035..58a32ea72a9 100644
--- a/chromium/ui/views/bubble/footnote_container_view.cc
+++ b/chromium/ui/views/bubble/footnote_container_view.cc
@@ -54,7 +54,10 @@ FootnoteContainerView::FootnoteContainerView(const gfx::Insets& margins,
SetLayoutManager(
std::make_unique<BoxLayout>(BoxLayout::kVertical, margins, 0));
SetCornerRadius(corner_radius);
- SetBorder(CreateSolidSidedBorder(1, 0, 0, 0, gfx::kGoogleGrey200));
+ SetBorder(CreateSolidSidedBorder(1, 0, 0, 0,
+ GetNativeTheme()->SystemDarkModeEnabled()
+ ? gfx::kGoogleGrey900
+ : gfx::kGoogleGrey200));
AddChildView(child_view);
SetVisible(child_view->visible());
}
@@ -62,9 +65,8 @@ FootnoteContainerView::FootnoteContainerView(const gfx::Insets& margins,
FootnoteContainerView::~FootnoteContainerView() = default;
void FootnoteContainerView::SetCornerRadius(float corner_radius) {
- // TODO(crbug.com/893598): Finalize dark mode color.
SkColor background_color = GetNativeTheme()->SystemDarkModeEnabled()
- ? gfx::kGoogleGrey800
+ ? SkColorSetRGB(0x32, 0x36, 0x39)
: gfx::kGoogleGrey050;
SetBackground(std::make_unique<HalfRoundedRectBackground>(background_color,
corner_radius));
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 0a06d9a9bd1..2f82d8e99e9 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -14,6 +14,7 @@
#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/cocoa/ns_view_ids.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/compositor/layer_owner.h"
#include "ui/views/cocoa/bridge_factory_host.h"
@@ -38,6 +39,7 @@ namespace views {
class BridgedNativeWidgetImpl;
class NativeWidgetMac;
+class TextInputHost;
// The portion of NativeWidgetMac that lives in the browser process. This
// communicates to the BridgedNativeWidgetImpl, which interacts with the Cocoa
@@ -86,6 +88,8 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
return bridge_factory_host_;
}
+ TextInputHost* text_input_host() const { return text_input_host_.get(); }
+
// A NSWindow that is guaranteed to exist in this process. If the bridge
// object for this host is in this process, then this points to the bridge's
// NSWindow. Otherwise, it mirrors the id and bounds of the child window.
@@ -122,6 +126,10 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
void InitWindow(const Widget::InitParams& params);
+ // Close the window immediately. This function may result in |this| being
+ // deleted.
+ void CloseWindowNow();
+
// Changes the bounds of the window and the hosted layer if present. The
// origin is a location in screen coordinates except for "child" windows,
// which are positioned relative to their parent. SetBounds() considers a
@@ -201,10 +209,18 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
static NSView* GetGlobalCaptureView();
private:
+ friend class TextInputHost;
+
void UpdateCompositorProperties();
void DestroyCompositor();
void RankNSViewsRecursive(View* view, std::map<NSView*, int>* rank) const;
+ // If we are accessing the BridgedNativeWidget through mojo, then
+ // |local_window_| is not the true window that is resized. This function
+ // updates the frame of |local_window_| to keep it in sync for any native
+ // calls that may use it (e.g, for context menu positioning).
+ void UpdateLocalWindowFrame(const gfx::Rect& frame);
+
// BridgedNativeWidgetHostHelper:
id GetNativeViewAccessible() override;
void DispatchKeyEvent(ui::KeyEvent* event) override;
@@ -213,8 +229,8 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
bool* found_word,
gfx::DecoratedText* decorated_word,
gfx::Point* baseline_point) override;
- double SheetPositionY() override;
views_bridge_mac::DragDropClient* GetDragDropClient() override;
+ ui::TextInputClient* GetTextInputClient() override;
// BridgeFactoryHost::Observer:
void OnBridgeFactoryHostDestroying(BridgeFactoryHost* host) override;
@@ -223,6 +239,7 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
void OnVisibilityChanged(bool visible) override;
void OnWindowNativeThemeChanged() override;
void OnViewSizeChanged(const gfx::Size& new_size) override;
+ bool GetSheetOffsetY(int32_t* offset_y) override;
void SetKeyboardAccessible(bool enabled) override;
void OnIsFirstResponderChanged(bool is_first_responder) override;
void OnMouseCaptureActiveChanged(bool capture_is_active) override;
@@ -268,8 +285,25 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
bool GetWindowFrameTitlebarHeight(bool* override_titlebar_height,
float* titlebar_height) override;
void OnFocusWindowToolbar() override;
+ void SetRemoteAccessibilityTokens(
+ const std::vector<uint8_t>& window_token,
+ const std::vector<uint8_t>& view_token) override;
+ bool GetRootViewAccessibilityToken(int64_t* pid,
+ std::vector<uint8_t>* token) override;
+ bool ValidateUserInterfaceItem(
+ int32_t command,
+ views_bridge_mac::mojom::ValidateUserInterfaceItemResultPtr* out_result)
+ override;
+ bool ExecuteCommand(int32_t command,
+ WindowOpenDisposition window_open_disposition,
+ bool is_before_first_responder,
+ bool* was_executed) override;
+ bool HandleAccelerator(const ui::Accelerator& accelerator,
+ bool require_priority_handler,
+ bool* was_handled) override;
// views_bridge_mac::mojom::BridgedNativeWidgetHost, synchronous callbacks:
+ void GetSheetOffsetY(GetSheetOffsetYCallback callback) override;
void DispatchKeyEventRemote(std::unique_ptr<ui::Event> event,
DispatchKeyEventRemoteCallback callback) override;
void DispatchKeyEventToMenuControllerRemote(
@@ -296,12 +330,21 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
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;
+ void GetRootViewAccessibilityToken(
+ GetRootViewAccessibilityTokenCallback callback) override;
+ void ValidateUserInterfaceItem(
+ int32_t command,
+ ValidateUserInterfaceItemCallback callback) override;
+ void ExecuteCommand(int32_t command,
+ WindowOpenDisposition window_open_disposition,
+ bool is_before_first_responder,
+ ExecuteCommandCallback callback) override;
+ void HandleAccelerator(const ui::Accelerator& accelerator,
+ bool require_priority_handler,
+ HandleAcceleratorCallback callback) override;
// DialogObserver:
- void OnDialogModelChanged() override;
+ void OnDialogChanged() override;
// FocusChangeListener:
void OnWillChangeFocus(View* focused_before, View* focused_now) override;
@@ -339,7 +382,10 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// The id that may be used to look up the NSView for |root_view_|.
const uint64_t root_view_id_;
- views::View* root_view_ = nullptr; // Weak. Owned by |native_widget_mac_|.
+
+ // Weak. Owned by |native_widget_mac_|.
+ views::View* root_view_ = nullptr;
+
std::unique_ptr<DragDropClientMac> drag_drop_client_;
// The mojo pointer to a BridgedNativeWidget, which may exist in another
@@ -364,8 +410,12 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// Window that is guaranteed to exist in this process (see GetLocalNSWindow).
base::scoped_nsobject<NativeWidgetMacNSWindow> local_window_;
+ // Id mapping for |local_window_|'s content NSView.
+ std::unique_ptr<ui::ScopedNSViewIdMapping> local_view_id_mapping_;
+
std::unique_ptr<TooltipManager> tooltip_manager_;
std::unique_ptr<ui::InputMethod> input_method_;
+ std::unique_ptr<TextInputHost> text_input_host_;
FocusManager* focus_manager_ = nullptr; // Weak. Owned by our Widget.
base::string16 window_title_;
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 6267200e448..a156f05df7f 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -7,17 +7,18 @@
#include <utility>
#include "base/mac/foundation_util.h"
+#include "mojo/public/cpp/bindings/strong_associated_binding.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"
-#include "ui/base/models/dialog_model.h"
#include "ui/compositor/recyclable_compositor_mac.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/mac/coordinate_conversion.h"
#include "ui/native_theme/native_theme_mac.h"
+#include "ui/views/cocoa/text_input_host.h"
#include "ui/views/cocoa/tooltip_manager_mac.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_controller.h"
@@ -39,6 +40,151 @@ namespace views {
namespace {
+// Dummy implementation of the BridgedNativeWidgetHost interface. This structure
+// exists to work around a bug wherein synchronous mojo calls to an associated
+// interface can hang if the interface request is unbound. This structure is
+// bound to the real host's interface, and then deletes itself only once the
+// underlying connection closes.
+// https://crbug.com/915572
+class BridgedNativeWidgetHostDummy
+ : public views_bridge_mac::mojom::BridgedNativeWidgetHost {
+ public:
+ BridgedNativeWidgetHostDummy() {}
+ ~BridgedNativeWidgetHostDummy() override {}
+
+ private:
+ void OnVisibilityChanged(bool visible) override {}
+ void OnWindowNativeThemeChanged() override {}
+ void OnViewSizeChanged(const gfx::Size& new_size) override {}
+ void SetKeyboardAccessible(bool enabled) 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 {}
+ void OnGestureEvent(std::unique_ptr<ui::Event> event) override {}
+ void OnWindowGeometryChanged(
+ const gfx::Rect& window_bounds_in_screen_dips,
+ const gfx::Rect& content_bounds_in_screen_dips) override {}
+ void OnWindowFullscreenTransitionStart(
+ bool target_fullscreen_state) override {}
+ void OnWindowFullscreenTransitionComplete(bool is_fullscreen) override {}
+ void OnWindowMiniaturizedChanged(bool miniaturized) override {}
+ void OnWindowDisplayChanged(const display::Display& display) override {}
+ void OnWindowWillClose() override {}
+ void OnWindowHasClosed() override {}
+ void OnWindowKeyStatusChanged(bool is_key,
+ bool is_content_first_responder,
+ bool full_keyboard_access_enabled) override {}
+ void DoDialogButtonAction(ui::DialogButton button) override {}
+ void OnFocusWindowToolbar() override {}
+ void SetRemoteAccessibilityTokens(
+ const std::vector<uint8_t>& window_token,
+ const std::vector<uint8_t>& view_token) override {}
+ void GetSheetOffsetY(GetSheetOffsetYCallback callback) override {
+ float offset_y = 0;
+ std::move(callback).Run(offset_y);
+ }
+ void DispatchKeyEventRemote(
+ std::unique_ptr<ui::Event> event,
+ DispatchKeyEventRemoteCallback callback) override {
+ bool event_handled = false;
+ std::move(callback).Run(event_handled);
+ }
+ void DispatchKeyEventToMenuControllerRemote(
+ std::unique_ptr<ui::Event> event,
+ DispatchKeyEventToMenuControllerRemoteCallback callback) override {
+ ui::KeyEvent* key_event = event->AsKeyEvent();
+ bool event_swallowed = false;
+ std::move(callback).Run(event_swallowed, key_event->handled());
+ }
+ void GetHasMenuController(GetHasMenuControllerCallback callback) override {
+ bool has_menu_controller = false;
+ std::move(callback).Run(has_menu_controller);
+ }
+ void GetIsDraggableBackgroundAt(
+ const gfx::Point& location_in_content,
+ GetIsDraggableBackgroundAtCallback callback) override {
+ bool is_draggable_background = false;
+ std::move(callback).Run(is_draggable_background);
+ }
+ void GetTooltipTextAt(const gfx::Point& location_in_content,
+ GetTooltipTextAtCallback callback) override {
+ base::string16 new_tooltip_text;
+ std::move(callback).Run(new_tooltip_text);
+ }
+ void GetIsFocusedViewTextual(
+ GetIsFocusedViewTextualCallback callback) override {
+ bool is_textual = false;
+ std::move(callback).Run(is_textual);
+ }
+ void GetWidgetIsModal(GetWidgetIsModalCallback callback) override {
+ bool widget_is_modal = false;
+ std::move(callback).Run(widget_is_modal);
+ }
+ void GetDialogButtonInfo(ui::DialogButton button,
+ GetDialogButtonInfoCallback callback) override {
+ bool exists = false;
+ base::string16 label;
+ bool is_enabled = false;
+ bool is_default = false;
+ std::move(callback).Run(exists, label, is_enabled, is_default);
+ }
+ void GetDoDialogButtonsExist(
+ GetDoDialogButtonsExistCallback callback) override {
+ bool buttons_exist = false;
+ std::move(callback).Run(buttons_exist);
+ }
+ void GetShouldShowWindowTitle(
+ GetShouldShowWindowTitleCallback callback) override {
+ bool should_show_window_title = false;
+ std::move(callback).Run(should_show_window_title);
+ }
+ void GetCanWindowBecomeKey(GetCanWindowBecomeKeyCallback callback) override {
+ bool can_window_become_key = false;
+ std::move(callback).Run(can_window_become_key);
+ }
+ void GetAlwaysRenderWindowAsKey(
+ GetAlwaysRenderWindowAsKeyCallback callback) override {
+ bool always_render_as_key = false;
+ std::move(callback).Run(always_render_as_key);
+ }
+ void GetCanWindowClose(GetCanWindowCloseCallback callback) override {
+ bool can_window_close = false;
+ std::move(callback).Run(can_window_close);
+ }
+ void GetWindowFrameTitlebarHeight(
+ GetWindowFrameTitlebarHeightCallback callback) override {
+ bool override_titlebar_height = false;
+ float titlebar_height = 0;
+ std::move(callback).Run(override_titlebar_height, titlebar_height);
+ }
+ void GetRootViewAccessibilityToken(
+ GetRootViewAccessibilityTokenCallback callback) override {
+ std::vector<uint8_t> token;
+ int64_t pid = 0;
+ std::move(callback).Run(pid, token);
+ }
+ void ValidateUserInterfaceItem(
+ int32_t command,
+ ValidateUserInterfaceItemCallback callback) override {
+ views_bridge_mac::mojom::ValidateUserInterfaceItemResultPtr result;
+ std::move(callback).Run(std::move(result));
+ }
+ void ExecuteCommand(int32_t command,
+ WindowOpenDisposition window_open_disposition,
+ bool is_before_first_responder,
+ ExecuteCommandCallback callback) override {
+ bool was_executed = false;
+ std::move(callback).Run(was_executed);
+ }
+ void HandleAccelerator(const ui::Accelerator& accelerator,
+ bool require_priority_handler,
+ HandleAcceleratorCallback callback) override {
+ bool was_handled = false;
+ std::move(callback).Run(was_handled);
+ }
+};
+
// Returns true if bounds passed to window in SetBounds should be treated as
// though they are in screen coordinates.
bool PositionWindowInScreenCoordinates(Widget* widget,
@@ -91,6 +237,7 @@ BridgedNativeWidgetHostImpl::BridgedNativeWidgetHostImpl(NativeWidgetMac* owner)
native_widget_mac_(owner),
root_view_id_(ui::NSViewIds::GetNewId()),
accessibility_focus_overrider_(this),
+ text_input_host_(new TextInputHost(this)),
host_mojo_binding_(this) {
DCHECK(GetIdToWidgetHostImplMap().find(widget_id_) ==
GetIdToWidgetHostImplMap().end());
@@ -102,11 +249,19 @@ BridgedNativeWidgetHostImpl::~BridgedNativeWidgetHostImpl() {
DCHECK(children_.empty());
if (bridge_factory_host_) {
bridge_ptr_.reset();
- host_mojo_binding_.Unbind();
bridge_factory_host_->RemoveObserver(this);
bridge_factory_host_ = nullptr;
}
+ // Workaround for https://crbug.com/915572
+ if (host_mojo_binding_.is_bound()) {
+ auto request = host_mojo_binding_.Unbind();
+ if (request.is_pending()) {
+ mojo::MakeStrongAssociatedBinding(
+ std::make_unique<BridgedNativeWidgetHostDummy>(), std::move(request));
+ }
+ }
+
// Ensure that |this| cannot be reached by its id while it is being destroyed.
auto found = GetIdToWidgetHostImplMap().find(widget_id_);
DCHECK(found != GetIdToWidgetHostImplMap().end());
@@ -152,8 +307,8 @@ BridgedNativeWidgetHostImpl::bridge() const {
void BridgedNativeWidgetHostImpl::CreateLocalBridge(
base::scoped_nsobject<NativeWidgetMacNSWindow> window) {
local_window_ = window;
- bridge_impl_ =
- std::make_unique<BridgedNativeWidgetImpl>(widget_id_, this, this);
+ bridge_impl_ = std::make_unique<BridgedNativeWidgetImpl>(
+ widget_id_, this, this, text_input_host_.get());
bridge_impl_->SetWindow(window);
}
@@ -173,14 +328,19 @@ void BridgedNativeWidgetHostImpl::CreateRemoteBridge(
local_window_create_params.get());
[local_window_ setBridgedNativeWidgetId:widget_id_];
[local_window_ setAlphaValue:0.0];
+ local_view_id_mapping_ = std::make_unique<ui::ScopedNSViewIdMapping>(
+ root_view_id_, [local_window_ contentView]);
}
// Initialize |bridge_ptr_| to point to a bridge created by |factory|.
views_bridge_mac::mojom::BridgedNativeWidgetHostAssociatedPtr host_ptr;
host_mojo_binding_.Bind(mojo::MakeRequest(&host_ptr),
ui::WindowResizeHelperMac::Get()->task_runner());
+ views_bridge_mac::mojom::TextInputHostAssociatedPtr text_input_host_ptr;
+ text_input_host_->BindRequest(mojo::MakeRequest(&text_input_host_ptr));
bridge_factory_host_->GetFactory()->CreateBridgedNativeWidget(
- widget_id_, mojo::MakeRequest(&bridge_ptr_), host_ptr.PassInterface());
+ widget_id_, mojo::MakeRequest(&bridge_ptr_), host_ptr.PassInterface(),
+ text_input_host_ptr.PassInterface());
// Create the window in its process, and attach it to its parent window.
bridge()->CreateWindow(std::move(window_create_params));
@@ -237,6 +397,7 @@ void BridgedNativeWidgetHostImpl::InitWindow(const Widget::InitParams& params) {
// set at all, the creator of the Widget is expected to call SetBounds()
// before calling Widget::Show() to avoid a kWindowSizeDeterminedLater-sized
// (i.e. 1x1) window appearing.
+ UpdateLocalWindowFrame(params.bounds);
bridge()->SetInitialBounds(params.bounds, widget->GetMinimumSize());
// TODO(ccameron): Correctly set these based |local_window_|.
@@ -248,7 +409,24 @@ void BridgedNativeWidgetHostImpl::InitWindow(const Widget::InitParams& params) {
bridge()->SetVisibilityState(WindowVisibilityState::kShowInactive);
}
+void BridgedNativeWidgetHostImpl::CloseWindowNow() {
+ bool is_out_of_process = !bridge_impl_;
+ // Note that CloseWindowNow may delete |this| for in-process windows.
+ if (bridge())
+ bridge()->CloseWindowNow();
+
+ // If it is out-of-process, then simulate the calls that would have been
+ // during window closure.
+ if (is_out_of_process) {
+ OnWindowWillClose();
+ while (!children_.empty())
+ children_.front()->CloseWindowNow();
+ OnWindowHasClosed();
+ }
+}
+
void BridgedNativeWidgetHostImpl::SetBounds(const gfx::Rect& bounds) {
+ UpdateLocalWindowFrame(bounds);
bridge()->SetBounds(bounds,
native_widget_mac_->GetWidget()->GetMinimumSize());
}
@@ -464,6 +642,13 @@ void BridgedNativeWidgetHostImpl::RankNSViewsRecursive(
RankNSViewsRecursive(view->child_at(i), rank);
}
+void BridgedNativeWidgetHostImpl::UpdateLocalWindowFrame(
+ const gfx::Rect& frame) {
+ if (!bridge_ptr_)
+ return;
+ [local_window_ setFrame:gfx::ScreenRectToNSRect(frame) display:NO animate:NO];
+}
+
// static
NSView* BridgedNativeWidgetHostImpl::GetGlobalCaptureView() {
// TODO(ccameron): This will not work across process boundaries.
@@ -493,15 +678,15 @@ bool BridgedNativeWidgetHostImpl::DispatchKeyEventToMenuController(
return false;
}
-double BridgedNativeWidgetHostImpl::SheetPositionY() {
- return native_widget_mac_->SheetPositionY();
-}
-
views_bridge_mac::DragDropClient*
BridgedNativeWidgetHostImpl::GetDragDropClient() {
return drag_drop_client_.get();
}
+ui::TextInputClient* BridgedNativeWidgetHostImpl::GetTextInputClient() {
+ return text_input_host_->GetTextInputClient();
+}
+
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetHostImpl, BridgeFactoryHost::Observer:
void BridgedNativeWidgetHostImpl::OnBridgeFactoryHostDestroying(
@@ -589,6 +774,11 @@ void BridgedNativeWidgetHostImpl::OnViewSizeChanged(const gfx::Size& new_size) {
root_view_->SetSize(new_size);
}
+bool BridgedNativeWidgetHostImpl::GetSheetOffsetY(int32_t* offset_y) {
+ *offset_y = native_widget_mac_->SheetOffsetY();
+ return true;
+}
+
void BridgedNativeWidgetHostImpl::SetKeyboardAccessible(bool enabled) {
views::FocusManager* focus_manager =
root_view_->GetWidget()->GetFocusManager();
@@ -686,15 +876,7 @@ bool BridgedNativeWidgetHostImpl::GetIsFocusedViewTextual(bool* is_textual) {
void BridgedNativeWidgetHostImpl::OnWindowGeometryChanged(
const gfx::Rect& new_window_bounds_in_screen,
const gfx::Rect& new_content_bounds_in_screen) {
- // If we are accessing the BridgedNativeWidget through mojo, then
- // |local_window_| is not the true window that was just resized. Update
- // the frame of |local_window_| to keep it in sync for any native calls
- // that may use it (e.g, for context menu positioning).
- if (bridge_ptr_) {
- [local_window_ setFrame:gfx::ScreenRectToNSRect(new_window_bounds_in_screen)
- display:NO
- animate:NO];
- }
+ UpdateLocalWindowFrame(new_window_bounds_in_screen);
bool window_has_moved =
new_window_bounds_in_screen.origin() != window_bounds_in_screen_.origin();
@@ -831,21 +1013,21 @@ bool BridgedNativeWidgetHostImpl::GetDialogButtonInfo(
bool* is_button_enabled,
bool* is_button_default) {
*button_exists = false;
- ui::DialogModel* model =
+ views::DialogDelegate* dialog =
root_view_->GetWidget()->widget_delegate()->AsDialogDelegate();
- if (!model || !(model->GetDialogButtons() & button))
+ if (!dialog || !(dialog->GetDialogButtons() & button))
return true;
*button_exists = true;
- *button_label = model->GetDialogButtonLabel(button);
- *is_button_enabled = model->IsDialogButtonEnabled(button);
- *is_button_default = button == model->GetDefaultDialogButton();
+ *button_label = dialog->GetDialogButtonLabel(button);
+ *is_button_enabled = dialog->IsDialogButtonEnabled(button);
+ *is_button_default = button == dialog->GetDefaultDialogButton();
return true;
}
bool BridgedNativeWidgetHostImpl::GetDoDialogButtonsExist(bool* buttons_exist) {
- ui::DialogModel* model =
+ views::DialogDelegate* dialog =
root_view_->GetWidget()->widget_delegate()->AsDialogDelegate();
- *buttons_exist = model && model->GetDialogButtons();
+ *buttons_exist = dialog && dialog->GetDialogButtons();
return true;
}
@@ -893,10 +1075,71 @@ void BridgedNativeWidgetHostImpl::OnFocusWindowToolbar() {
native_widget_mac_->OnFocusWindowToolbar();
}
+void BridgedNativeWidgetHostImpl::SetRemoteAccessibilityTokens(
+ const std::vector<uint8_t>& window_token,
+ const std::vector<uint8_t>& view_token) {
+ 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()];
+}
+
+bool BridgedNativeWidgetHostImpl::GetRootViewAccessibilityToken(
+ int64_t* pid,
+ std::vector<uint8_t>* token) {
+ *pid = getpid();
+ id element_id = GetNativeViewAccessible();
+ *token = ui::RemoteAccessibility::GetTokenForLocalElement(element_id);
+ return true;
+}
+
+bool BridgedNativeWidgetHostImpl::ValidateUserInterfaceItem(
+ int32_t command,
+ views_bridge_mac::mojom::ValidateUserInterfaceItemResultPtr* out_result) {
+ *out_result = views_bridge_mac::mojom::ValidateUserInterfaceItemResult::New();
+ native_widget_mac_->ValidateUserInterfaceItem(command, out_result->get());
+ return true;
+}
+
+bool BridgedNativeWidgetHostImpl::ExecuteCommand(
+ int32_t command,
+ WindowOpenDisposition window_open_disposition,
+ bool is_before_first_responder,
+ bool* was_executed) {
+ *was_executed = native_widget_mac_->ExecuteCommand(
+ command, window_open_disposition, is_before_first_responder);
+ return true;
+}
+
+bool BridgedNativeWidgetHostImpl::HandleAccelerator(
+ const ui::Accelerator& accelerator,
+ bool require_priority_handler,
+ bool* was_handled) {
+ *was_handled = false;
+ if (Widget* widget = native_widget_mac_->GetWidget()) {
+ if (require_priority_handler &&
+ !widget->GetFocusManager()->HasPriorityHandler(accelerator)) {
+ return true;
+ }
+ *was_handled = widget->GetFocusManager()->ProcessAccelerator(accelerator);
+ }
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetHostImpl,
// views_bridge_mac::mojom::BridgedNativeWidgetHost synchronous callbacks:
+void BridgedNativeWidgetHostImpl::GetSheetOffsetY(
+ GetSheetOffsetYCallback callback) {
+ int32_t offset_y = 0;
+ GetSheetOffsetY(&offset_y);
+ std::move(callback).Run(offset_y);
+}
+
void BridgedNativeWidgetHostImpl::DispatchKeyEventRemote(
std::unique_ptr<ui::Event> event,
DispatchKeyEventRemoteCallback callback) {
@@ -1004,27 +1247,46 @@ void BridgedNativeWidgetHostImpl::GetWindowFrameTitlebarHeight(
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()];
+void BridgedNativeWidgetHostImpl::GetRootViewAccessibilityToken(
+ GetRootViewAccessibilityTokenCallback callback) {
+ std::vector<uint8_t> token;
+ int64_t pid;
+ GetRootViewAccessibilityToken(&pid, &token);
+ std::move(callback).Run(pid, token);
+}
- id element_id = GetNativeViewAccessible();
- std::move(callback).Run(
- getpid(), ui::RemoteAccessibility::GetTokenForLocalElement(element_id));
+void BridgedNativeWidgetHostImpl::ValidateUserInterfaceItem(
+ int32_t command,
+ ValidateUserInterfaceItemCallback callback) {
+ views_bridge_mac::mojom::ValidateUserInterfaceItemResultPtr result;
+ ValidateUserInterfaceItem(command, &result);
+ std::move(callback).Run(std::move(result));
+}
+
+void BridgedNativeWidgetHostImpl::ExecuteCommand(
+ int32_t command,
+ WindowOpenDisposition window_open_disposition,
+ bool is_before_first_responder,
+ ExecuteCommandCallback callback) {
+ bool was_executed = false;
+ ExecuteCommand(command, window_open_disposition, is_before_first_responder,
+ &was_executed);
+ std::move(callback).Run(was_executed);
+}
+
+void BridgedNativeWidgetHostImpl::HandleAccelerator(
+ const ui::Accelerator& accelerator,
+ bool require_priority_handler,
+ HandleAcceleratorCallback callback) {
+ bool was_handled = false;
+ HandleAccelerator(accelerator, require_priority_handler, &was_handled);
+ std::move(callback).Run(was_handled);
}
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetHostImpl, DialogObserver:
-void BridgedNativeWidgetHostImpl::OnDialogModelChanged() {
+void BridgedNativeWidgetHostImpl::OnDialogChanged() {
// Note it's only necessary to clear the TouchBar. If the OS needs it again,
// a new one will be created.
bridge()->ClearTouchBar();
@@ -1040,16 +1302,15 @@ void BridgedNativeWidgetHostImpl::OnDidChangeFocus(View* focused_before,
View* focused_now) {
ui::InputMethod* input_method =
native_widget_mac_->GetWidget()->GetInputMethod();
- if (input_method) {
- ui::TextInputClient* input_client = input_method->GetTextInputClient();
- // Sanity check: When focus moves away from the widget (i.e. |focused_now|
- // is nil), then the textInputClient will be cleared.
- DCHECK(!!focused_now || !input_client);
- // TODO(ccameron): TextInputClient is not handled across process borders
- // yet.
- if (bridge_impl_)
- bridge_impl_->SetTextInputClient(input_client);
- }
+ if (!input_method)
+ return;
+
+ ui::TextInputClient* new_text_input_client =
+ input_method->GetTextInputClient();
+ // Sanity check: When focus moves away from the widget (i.e. |focused_now|
+ // is nil), then the textInputClient will be cleared.
+ DCHECK(!!focused_now || !new_text_input_client);
+ text_input_host_->SetTextInputClient(new_text_input_client);
}
////////////////////////////////////////////////////////////////////////////////
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 8617012253b..618c3cfe1c6 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
@@ -16,7 +16,6 @@
#import "ui/base/test/windowed_nsnotification_observer.h"
#import "ui/events/test/cocoa_test_event_utils.h"
#include "ui/views/cocoa/bridged_native_widget_host_impl.h"
-#include "ui/views/test/views_interactive_ui_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/native_widget_mac.h"
#include "ui/views/window/native_frame_view.h"
@@ -41,14 +40,15 @@ class ResizableDelegateView : public WidgetDelegateView {
} // namespace
-class BridgedNativeWidgetUITest : public test::WidgetTest {
+class BridgedNativeWidgetUITest : public WidgetTest {
public:
BridgedNativeWidgetUITest() = default;
// testing::Test:
void SetUp() override {
- ViewsInteractiveUITestBase::InteractiveSetUp();
+ SetUpForInteractiveTests();
WidgetTest::SetUp();
+
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
index 00df4d7ab79..2d9008b8891 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -26,6 +26,7 @@
#include "ui/events/test/cocoa_test_event_utils.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/views/cocoa/bridged_native_widget_host_impl.h"
+#import "ui/views/cocoa/text_input_host.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/controls/textfield/textfield_model.h"
@@ -299,7 +300,7 @@ class MockNativeWidgetMac : public NativeWidgetMac {
explicit MockNativeWidgetMac(internal::NativeWidgetDelegate* delegate)
: NativeWidgetMac(delegate) {}
using NativeWidgetMac::bridge_impl;
- using NativeWidgetMac::bridge_host_for_testing;
+ using NativeWidgetMac::bridge_host;
// internal::NativeWidgetPrivate:
void InitNativeWidget(const Widget::InitParams& params) override {
@@ -311,19 +312,19 @@ class MockNativeWidgetMac : public NativeWidgetMac {
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO]);
- bridge_host_for_testing()->CreateLocalBridge(window);
+ bridge_host()->CreateLocalBridge(window);
if (auto* parent =
BridgedNativeWidgetHostImpl::GetFromNativeView(params.parent)) {
- bridge_host_for_testing()->SetParent(parent);
+ bridge_host()->SetParent(parent);
}
- bridge_host_for_testing()->InitWindow(params);
+ bridge_host()->InitWindow(params);
// Usually the bridge gets initialized here. It is skipped to run extra
// checks in tests, and so that a second window isn't created.
- delegate()->OnNativeWidgetCreated(true);
+ delegate()->OnNativeWidgetCreated();
// To allow events to dispatch to a view, it needs a way to get focus.
- bridge_host_for_testing()->SetFocusManager(GetWidget()->GetFocusManager());
+ bridge_host()->SetFocusManager(GetWidget()->GetFocusManager());
}
void ReorderNativeViews() override {
@@ -350,7 +351,7 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
return native_widget_mac_->bridge_impl();
}
BridgedNativeWidgetHostImpl* bridge_host() {
- return native_widget_mac_->bridge_host_for_testing();
+ return native_widget_mac_->bridge_host();
}
// Generate an autoreleased KeyDown NSEvent* in |widget_| for pressing the
@@ -550,7 +551,7 @@ Textfield* BridgedNativeWidgetTest::InstallTextField(
// schedules a task to flash the cursor, so this requires |message_loop_|.
textfield->RequestFocus();
- [ns_view_ setTextInputClient:textfield];
+ bridge_host()->text_input_host()->SetTextInputClient(textfield);
// Initialize the dummy text view. Initializing this with NSZeroRect causes
// weird NSTextView behavior on OSX 10.9.
@@ -591,7 +592,7 @@ NSRange BridgedNativeWidgetTest::GetExpectedSelectionRange() {
void BridgedNativeWidgetTest::SetSelectionRange(NSRange range) {
ui::TextInputClient* client = [ns_view_ textInputClient];
- client->SetSelectionRange(gfx::Range(range));
+ client->SetEditableSelectionRange(gfx::Range(range));
[dummy_text_view_ setSelectedRange:range];
}
@@ -607,7 +608,7 @@ void BridgedNativeWidgetTest::MakeSelection(int start, int end) {
// Although a gfx::Range is directed, the underlying model will not choose an
// affinity until the cursor is moved.
- client->SetSelectionRange(range);
+ client->SetEditableSelectionRange(range);
// Set the range without an affinity. The first @selector sent to the text
// field determines the affinity. Note that Range::ToNSRange() may discard
@@ -930,7 +931,7 @@ TEST_F(BridgedNativeWidgetTest, InputContext) {
EXPECT_FALSE([ns_view_ inputContext]);
InstallTextField(test_string, ui::TEXT_INPUT_TYPE_TEXT);
EXPECT_TRUE([ns_view_ inputContext]);
- [ns_view_ setTextInputClient:nil];
+ bridge_host()->text_input_host()->SetTextInputClient(nullptr);
EXPECT_FALSE([ns_view_ inputContext]);
InstallTextField(test_string, ui::TEXT_INPUT_TYPE_NONE);
EXPECT_FALSE([ns_view_ inputContext]);
@@ -1339,7 +1340,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_DeleteCommands) {
// Test that we don't crash during an action message even if the TextInputClient
// is nil. Regression test for crbug.com/615745.
TEST_F(BridgedNativeWidgetTest, NilTextInputClient) {
- [ns_view_ setTextInputClient:nil];
+ bridge_host()->text_input_host()->SetTextInputClient(nullptr);
NSMutableArray* selectors = [NSMutableArray array];
[selectors addObjectsFromArray:kMoveActions];
[selectors addObjectsFromArray:kSelectActions];
@@ -1751,7 +1752,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) {
bool saw_update_windows = false;
base::RepeatingClosure update_windows_closure = base::BindRepeating(
[](bool* saw_update_windows, BridgedContentView* view,
- Textfield* textfield) {
+ BridgedNativeWidgetHostImpl* host, Textfield* textfield) {
// Ensure updateWindows is not invoked recursively.
EXPECT_FALSE(*saw_update_windows);
*saw_update_windows = true;
@@ -1768,7 +1769,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) {
// reacting to InsertChar could theoretically do this, but toolkit-views
// DCHECKs if there is recursive event dispatch, so call
// setTextInputClient directly.
- [view setTextInputClient:textfield];
+ host->text_input_host()->SetTextInputClient(textfield);
// Finally simulate what -[NSApp updateWindows] should _actually_ do,
// which is to update the input context (from the first responder).
@@ -1777,20 +1778,21 @@ TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) {
// Now, the |textfield| set above should have been set again.
EXPECT_TRUE(g_fake_current_input_context);
},
- &saw_update_windows, ns_view_, textfield);
+ &saw_update_windows, ns_view_, bridge_host(), textfield);
SetHandleKeyEventCallback(base::BindRepeating(
- [](int* saw_return_count, BridgedContentView* view, Textfield* textfield,
+ [](int* saw_return_count, BridgedContentView* view,
+ BridgedNativeWidgetHostImpl* host, Textfield* textfield,
const ui::KeyEvent& event) {
if (event.key_code() == ui::VKEY_RETURN) {
*saw_return_count += 1;
// Simulate Textfield::OnBlur() by clearing the input method.
// Textfield needs to be in a Widget to do this normally.
- [view setTextInputClient:nullptr];
+ host->text_input_host()->SetTextInputClient(nullptr);
}
return false;
},
- &vkey_return_count, ns_view_));
+ &vkey_return_count, ns_view_, bridge_host()));
// Starting text (just insert it).
[ns_view_ insertText:@"ㅂ" replacementRange:NSMakeRange(NSNotFound, 0)];
diff --git a/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm b/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
index 4f49c8bd382..f78a6f0af56 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -130,7 +130,7 @@ class DragDropView : public View {
// View:
bool GetDropFormats(
int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) override {
+ std::set<ui::ClipboardFormatType>* format_types) override {
*formats |= formats_;
return true;
}
diff --git a/chromium/ui/views/cocoa/text_input_host.h b/chromium/ui/views/cocoa/text_input_host.h
new file mode 100644
index 00000000000..d1aa622a4b2
--- /dev/null
+++ b/chromium/ui/views/cocoa/text_input_host.h
@@ -0,0 +1,91 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_COCOA_TEXT_INPUT_HOST_H_
+#define UI_VIEWS_COCOA_TEXT_INPUT_HOST_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "ui/views/views_export.h"
+#include "ui/views_bridge_mac/mojo/text_input_host.mojom.h"
+
+namespace ui {
+class TextInputClient;
+} // namespace ui
+
+namespace views {
+
+class BridgedNativeWidgetHostImpl;
+
+class VIEWS_EXPORT TextInputHost
+ : public views_bridge_mac::mojom::TextInputHost {
+ public:
+ TextInputHost(BridgedNativeWidgetHostImpl* host_impl);
+ ~TextInputHost() override;
+ void BindRequest(
+ views_bridge_mac::mojom::TextInputHostAssociatedRequest request);
+
+ // Set the current TextInputClient.
+ void SetTextInputClient(ui::TextInputClient* new_text_input_client);
+
+ // Return a pointer to the host's ui::TextInputClient.
+ // TODO(ccameron): Remove the need for this call.
+ ui::TextInputClient* GetTextInputClient() const;
+
+ private:
+ // views_bridge_mac::mojom::TextInputHost:
+ bool HasClient(bool* out_has_client) override;
+ bool HasInputContext(bool* out_has_input_context) override;
+ bool IsRTL(bool* out_is_rtl) override;
+ bool GetSelectionRange(gfx::Range* out_range) override;
+ bool GetSelectionText(bool* out_result, base::string16* out_text) override;
+ void InsertText(const base::string16& text, bool as_character) override;
+ void DeleteRange(const gfx::Range& range) override;
+ void SetCompositionText(const base::string16& text,
+ const gfx::Range& selected_range,
+ const gfx::Range& replacement_range) override;
+ void ConfirmCompositionText() override;
+ bool HasCompositionText(bool* out_has_composition_text) override;
+ bool GetCompositionTextRange(gfx::Range* out_composition_range) override;
+ bool GetAttributedSubstringForRange(const gfx::Range& requested_range,
+ base::string16* out_text,
+ gfx::Range* out_actual_range) override;
+ bool GetFirstRectForRange(const gfx::Range& requested_range,
+ gfx::Rect* out_rect,
+ gfx::Range* out_actual_range) override;
+
+ // views_bridge_mac::mojom::TextInputHost synchronous methods:
+ void HasClient(HasClientCallback callback) override;
+ void HasInputContext(HasInputContextCallback callback) override;
+ void IsRTL(IsRTLCallback callback) override;
+ void GetSelectionRange(GetSelectionRangeCallback callback) override;
+ void GetSelectionText(GetSelectionTextCallback callback) override;
+ void HasCompositionText(HasCompositionTextCallback callback) override;
+ void GetCompositionTextRange(
+ GetCompositionTextRangeCallback callback) override;
+ void GetAttributedSubstringForRange(
+ const gfx::Range& requested_range,
+ GetAttributedSubstringForRangeCallback callback) override;
+ void GetFirstRectForRange(const gfx::Range& requested_range,
+ GetFirstRectForRangeCallback callback) override;
+
+ // Weak. If non-null the TextInputClient of the currently focused views::View
+ // in the hierarchy rooted at the root view of |host_impl_|. Owned by the
+ // focused views::View.
+ ui::TextInputClient* text_input_client_ = nullptr;
+
+ // The TextInputClient about to be set. Requests for a new -inputContext will
+ // use this, but while the input is changing the NSView still needs to service
+ // IME requests using the old |text_input_client_|.
+ ui::TextInputClient* pending_text_input_client_ = nullptr;
+
+ BridgedNativeWidgetHostImpl* const host_impl_;
+
+ mojo::AssociatedBinding<views_bridge_mac::mojom::TextInputHost> mojo_binding_;
+ DISALLOW_COPY_AND_ASSIGN(TextInputHost);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_COCOA_TEXT_INPUT_HOST_H_
diff --git a/chromium/ui/views/cocoa/text_input_host.mm b/chromium/ui/views/cocoa/text_input_host.mm
new file mode 100644
index 00000000000..9b7d9abd514
--- /dev/null
+++ b/chromium/ui/views/cocoa/text_input_host.mm
@@ -0,0 +1,408 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/cocoa/text_input_host.h"
+
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/views/cocoa/bridged_native_widget_host_impl.h"
+#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
+
+namespace {
+
+// Returns the boundary rectangle for composition characters in the
+// |requested_range|. Sets |actual_range| corresponding to the returned
+// rectangle. For cases, where there is no composition text or the
+// |requested_range| lies outside the composition range, a zero width rectangle
+// corresponding to the caret bounds is returned. Logic used is similar to
+// RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange(...).
+gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client,
+ const gfx::Range& requested_range,
+ gfx::Range* actual_range) {
+ // NSRange doesn't support reversed ranges.
+ DCHECK(!requested_range.is_reversed());
+ DCHECK(actual_range);
+
+ // Set up default return values, to be returned in case of unusual cases.
+ gfx::Rect default_rect;
+ *actual_range = gfx::Range::InvalidRange();
+ if (!client)
+ return default_rect;
+
+ default_rect = client->GetCaretBounds();
+ default_rect.set_width(0);
+
+ // If possible, modify actual_range to correspond to caret position.
+ gfx::Range selection_range;
+ if (client->GetEditableSelectionRange(&selection_range)) {
+ // Caret bounds correspond to end index of selection_range.
+ *actual_range = gfx::Range(selection_range.end());
+ }
+
+ gfx::Range composition_range;
+ if (!client->HasCompositionText() ||
+ !client->GetCompositionTextRange(&composition_range) ||
+ !composition_range.Contains(requested_range))
+ return default_rect;
+
+ DCHECK(!composition_range.is_reversed());
+
+ const size_t from = requested_range.start() - composition_range.start();
+ const size_t to = requested_range.end() - composition_range.start();
+
+ // Pick the first character's bounds as the initial rectangle, then grow it to
+ // the full |requested_range| if possible.
+ const bool request_is_composition_end = from == composition_range.length();
+ const size_t first_index = request_is_composition_end ? from - 1 : from;
+ gfx::Rect union_rect;
+ if (!client->GetCompositionCharacterBounds(first_index, &union_rect))
+ return default_rect;
+
+ // If requested_range is empty, return a zero width rectangle corresponding to
+ // it.
+ if (from == to) {
+ if (request_is_composition_end &&
+ client->GetTextDirection() != base::i18n::RIGHT_TO_LEFT) {
+ // In case of an empty requested range at end of composition, return the
+ // rectangle to the right of the last compositioned character.
+ union_rect.set_origin(union_rect.top_right());
+ }
+ union_rect.set_width(0);
+ *actual_range = requested_range;
+ return union_rect;
+ }
+
+ // Toolkit-views textfields are always single-line, so no need to check for
+ // line breaks.
+ for (size_t i = from + 1; i < to; i++) {
+ gfx::Rect current_rect;
+ if (client->GetCompositionCharacterBounds(i, &current_rect)) {
+ union_rect.Union(current_rect);
+ } else {
+ *actual_range =
+ gfx::Range(requested_range.start(), i + composition_range.start());
+ return union_rect;
+ }
+ }
+ *actual_range = requested_range;
+ return union_rect;
+}
+
+// Returns the string corresponding to |requested_range| for the given |client|.
+// If a gfx::Range::InvalidRange() is passed, the full string stored by |client|
+// is returned. Sets |actual_range| corresponding to the returned string.
+base::string16 AttributedSubstringForRangeHelper(
+ const ui::TextInputClient* client,
+ const gfx::Range& requested_range,
+ gfx::Range* actual_range) {
+ // NSRange doesn't support reversed ranges.
+ DCHECK(!requested_range.is_reversed());
+ DCHECK(actual_range);
+
+ base::string16 substring;
+ gfx::Range text_range;
+ *actual_range = gfx::Range::InvalidRange();
+ if (!client || !client->GetTextRange(&text_range))
+ return substring;
+
+ // gfx::Range::Intersect() behaves a bit weirdly. If B is an empty range
+ // contained inside a non-empty range A, B intersection A returns
+ // gfx::Range::InvalidRange(), instead of returning B.
+ *actual_range = text_range.Contains(requested_range)
+ ? requested_range
+ : text_range.Intersect(requested_range);
+
+ // This is a special case for which the complete string should should be
+ // returned. NSTextView also follows this, though the same is not mentioned in
+ // NSTextInputClient documentation.
+ if (!requested_range.IsValid())
+ *actual_range = text_range;
+
+ client->GetTextFromRange(*actual_range, &substring);
+ return substring;
+}
+
+}
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// TextInputHost, public:
+
+TextInputHost::TextInputHost(BridgedNativeWidgetHostImpl* host_impl)
+ : host_impl_(host_impl), mojo_binding_(this) {}
+
+TextInputHost::~TextInputHost() {}
+
+void TextInputHost::BindRequest(
+ views_bridge_mac::mojom::TextInputHostAssociatedRequest request) {
+ mojo_binding_.Bind(std::move(request),
+ ui::WindowResizeHelperMac::Get()->task_runner());
+}
+
+ui::TextInputClient* TextInputHost::GetTextInputClient() const {
+ return text_input_client_;
+}
+
+void TextInputHost::SetTextInputClient(
+ ui::TextInputClient* new_text_input_client) {
+ if (pending_text_input_client_ == new_text_input_client)
+ return;
+
+ // This method may cause the IME window to dismiss, which may cause it to
+ // insert text (e.g. to replace marked text with "real" text). That should
+ // happen in the old -inputContext (which AppKit stores a reference to).
+ // Unfortunately, the only way to invalidate the the old -inputContext is to
+ // invoke -[NSApp updateWindows], which also wants a reference to the _new_
+ // -inputContext. So put the new inputContext in |pendingTextInputClient_| and
+ // only use it for -inputContext.
+ ui::TextInputClient* old_text_input_client = text_input_client_;
+
+ // Since dismissing an IME may insert text, a misbehaving IME or a
+ // ui::TextInputClient that acts on InsertChar() to change focus a second time
+ // may invoke -setTextInputClient: recursively; with [NSApp updateWindows]
+ // still on the stack. Calling [NSApp updateWindows] recursively may upset
+ // an IME. Since the rest of this method is only to decide whether to call
+ // updateWindows, and we're already calling it, just bail out.
+ if (text_input_client_ != pending_text_input_client_) {
+ pending_text_input_client_ = new_text_input_client;
+ return;
+ }
+
+ // Start by assuming no need to invoke -updateWindows.
+ text_input_client_ = new_text_input_client;
+ pending_text_input_client_ = new_text_input_client;
+
+ if (host_impl_->bridge_impl_ &&
+ host_impl_->bridge_impl_->NeedsUpdateWindows()) {
+ text_input_client_ = old_text_input_client;
+ [NSApp updateWindows];
+ // Note: |pending_text_input_client_| (and therefore +[NSTextInputContext
+ // currentInputContext] may have changed if called recursively.
+ text_input_client_ = pending_text_input_client_;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TextInputHost, views_bridge_mac::mojom::TextInputHost:
+
+bool TextInputHost::HasClient(bool* out_has_client) {
+ *out_has_client = text_input_client_ != nullptr;
+ return true;
+}
+
+bool TextInputHost::HasInputContext(bool* out_has_input_context) {
+ *out_has_input_context = false;
+
+ // If the textInputClient_ does not exist, return nil since this view does not
+ // conform to NSTextInputClient protocol.
+ if (!pending_text_input_client_)
+ return true;
+
+ // If a menu is active, and -[NSView interpretKeyEvents:] asks for the
+ // input context, return nil. This ensures the action message is sent to
+ // the view, rather than any NSTextInputClient a subview has installed.
+ bool has_menu_controller = false;
+ host_impl_->GetHasMenuController(&has_menu_controller);
+ if (has_menu_controller)
+ return true;
+
+ // When not in an editable mode, or while entering passwords
+ // (http://crbug.com/23219), we don't want to show IME candidate windows.
+ // Returning nil prevents this view from getting messages defined as part of
+ // the NSTextInputClient protocol.
+ switch (pending_text_input_client_->GetTextInputType()) {
+ case ui::TEXT_INPUT_TYPE_NONE:
+ case ui::TEXT_INPUT_TYPE_PASSWORD:
+ return true;
+ default:
+ *out_has_input_context = true;
+ }
+ return true;
+}
+
+bool TextInputHost::IsRTL(bool* out_is_rtl) {
+ *out_is_rtl = text_input_client_ && text_input_client_->GetTextDirection() ==
+ base::i18n::RIGHT_TO_LEFT;
+ return true;
+}
+
+bool TextInputHost::GetSelectionRange(gfx::Range* out_range) {
+ if (!text_input_client_ ||
+ !text_input_client_->GetEditableSelectionRange(out_range)) {
+ *out_range = gfx::Range::InvalidRange();
+ }
+ return true;
+}
+
+bool TextInputHost::GetSelectionText(bool* out_result,
+ base::string16* out_text) {
+ *out_result = false;
+ if (!text_input_client_)
+ return true;
+ gfx::Range selection_range;
+ if (!text_input_client_->GetEditableSelectionRange(&selection_range))
+ return true;
+ base::string16 text;
+ *out_result = text_input_client_->GetTextFromRange(selection_range, &text);
+ return true;
+}
+
+void TextInputHost::InsertText(const base::string16& text, bool as_character) {
+ if (!text_input_client_)
+ return;
+ if (as_character) {
+ // If a single character is inserted by keyDown's call to
+ // interpretKeyEvents: then use InsertChar() to allow editing events to be
+ // merged. We use ui::VKEY_UNKNOWN as the key code since it's not feasible
+ // to determine the correct key code for each unicode character. Also a
+ // correct keycode is not needed in the current context. Send ui::EF_NONE as
+ // the key modifier since |text| already accounts for the pressed key
+ // modifiers.
+ text_input_client_->InsertChar(ui::KeyEvent(
+ text[0], ui::VKEY_UNKNOWN, ui::DomCode::NONE, ui::EF_NONE));
+ } else {
+ text_input_client_->InsertText(text);
+ }
+}
+
+void TextInputHost::DeleteRange(const gfx::Range& range) {
+ if (!text_input_client_)
+ return;
+ text_input_client_->DeleteRange(range);
+}
+
+void TextInputHost::SetCompositionText(const base::string16& text,
+ const gfx::Range& selected_range,
+ const gfx::Range& replacement_range) {
+ if (!text_input_client_)
+ return;
+
+ text_input_client_->DeleteRange(replacement_range);
+ ui::CompositionText composition;
+ composition.text = text;
+ composition.selection = selected_range;
+
+ // Add an underline with text color and a transparent background to the
+ // composition text. TODO(karandeepb): On Cocoa textfields, the target clause
+ // of the composition has a thick underlines. The composition text also has
+ // discontinous underlines for different clauses. This is also supported in
+ // the Chrome renderer. Add code to extract underlines from |text| once our
+ // render text implementation supports thick underlines and discontinous
+ // underlines for consecutive characters. See http://crbug.com/612675.
+ composition.ime_text_spans.push_back(
+ ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 0, text.length(),
+ ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT));
+ text_input_client_->SetCompositionText(composition);
+}
+
+void TextInputHost::ConfirmCompositionText() {
+ if (!text_input_client_)
+ return;
+ text_input_client_->ConfirmCompositionText();
+}
+
+bool TextInputHost::HasCompositionText(bool* out_has_composition_text) {
+ *out_has_composition_text = false;
+ if (!text_input_client_)
+ return true;
+ *out_has_composition_text = text_input_client_->HasCompositionText();
+ return true;
+ return true;
+}
+
+bool TextInputHost::GetCompositionTextRange(gfx::Range* out_composition_range) {
+ *out_composition_range = gfx::Range::InvalidRange();
+ if (!text_input_client_)
+ return true;
+ if (!text_input_client_->HasCompositionText())
+ return true;
+ text_input_client_->GetCompositionTextRange(out_composition_range);
+ return true;
+}
+
+bool TextInputHost::GetAttributedSubstringForRange(
+ const gfx::Range& requested_range,
+ base::string16* out_text,
+ gfx::Range* out_actual_range) {
+ *out_text = AttributedSubstringForRangeHelper(
+ text_input_client_, requested_range, out_actual_range);
+ return true;
+}
+
+bool TextInputHost::GetFirstRectForRange(const gfx::Range& requested_range,
+ gfx::Rect* out_rect,
+ gfx::Range* out_actual_range) {
+ *out_rect = GetFirstRectForRangeHelper(text_input_client_, requested_range,
+ out_actual_range);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TextInputHost, views_bridge_mac::mojom::TextInputHost synchronous methods:
+
+void TextInputHost::HasClient(HasClientCallback callback) {
+ bool has_client = false;
+ HasClient(&has_client);
+ std::move(callback).Run(has_client);
+}
+
+void TextInputHost::HasInputContext(HasInputContextCallback callback) {
+ bool has_input_context = false;
+ HasClient(&has_input_context);
+ std::move(callback).Run(has_input_context);
+}
+
+void TextInputHost::IsRTL(IsRTLCallback callback) {
+ bool is_rtl = false;
+ IsRTL(&is_rtl);
+ std::move(callback).Run(is_rtl);
+}
+
+void TextInputHost::GetSelectionRange(GetSelectionRangeCallback callback) {
+ gfx::Range range = gfx::Range::InvalidRange();
+ GetSelectionRange(&range);
+ std::move(callback).Run(range);
+}
+
+void TextInputHost::GetSelectionText(GetSelectionTextCallback callback) {
+ bool result = false;
+ base::string16 text;
+ GetSelectionText(&result, &text);
+ std::move(callback).Run(result, text);
+}
+
+void TextInputHost::HasCompositionText(HasCompositionTextCallback callback) {
+ bool has_composition_text = false;
+ IsRTL(&has_composition_text);
+ std::move(callback).Run(has_composition_text);
+}
+
+void TextInputHost::GetCompositionTextRange(
+ GetCompositionTextRangeCallback callback) {
+ gfx::Range range = gfx::Range::InvalidRange();
+ GetCompositionTextRange(&range);
+ std::move(callback).Run(range);
+}
+
+void TextInputHost::GetAttributedSubstringForRange(
+ const gfx::Range& requested_range,
+ GetAttributedSubstringForRangeCallback callback) {
+ base::string16 text;
+ gfx::Range actual_range = gfx::Range::InvalidRange();
+ GetAttributedSubstringForRange(requested_range, &text, &actual_range);
+ std::move(callback).Run(text, actual_range);
+}
+
+void TextInputHost::GetFirstRectForRange(
+ const gfx::Range& requested_range,
+ GetFirstRectForRangeCallback callback) {
+ gfx::Rect rect;
+ gfx::Range actual_range;
+ GetFirstRectForRange(requested_range, &rect, &actual_range);
+ std::move(callback).Run(rect, actual_range);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc
index ad5ab5f0470..06e6422b365 100644
--- a/chromium/ui/views/controls/button/button.cc
+++ b/chromium/ui/views/controls/button/button.cc
@@ -492,10 +492,9 @@ void Button::RemovedFromWidget() {
}
std::unique_ptr<InkDrop> Button::CreateInkDrop() {
- std::unique_ptr<views::InkDropImpl> ink_drop = CreateDefaultInkDropImpl();
+ std::unique_ptr<InkDrop> ink_drop = InkDropHostView::CreateInkDrop();
ink_drop->SetShowHighlightOnFocus(!focus_ring_);
- ink_drop->SetAutoHighlightModeForPlatform();
- return std::move(ink_drop);
+ return ink_drop;
}
SkColor Button::GetInkDropBaseColor() const {
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index 1b688c6184e..d02b9477581 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -17,6 +17,7 @@
#include "ui/native_theme/native_theme.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/animation/ink_drop_impl.h"
+#include "ui/views/animation/ink_drop_mask.h"
#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/controls/focus_ring.h"
@@ -36,7 +37,6 @@ Checkbox::Checkbox(const base::string16& label, ButtonListener* listener)
: LabelButton(listener, label), checked_(false), label_ax_id_(0) {
SetHorizontalAlignment(gfx::ALIGN_LEFT);
SetFocusForPlatform();
- SetFocusPainter(nullptr);
set_request_focus_on_press(false);
SetInkDropMode(InkDropMode::ON);
@@ -108,7 +108,6 @@ void Checkbox::OnNativeThemeChanged(const ui::NativeTheme* theme) {
}
std::unique_ptr<InkDrop> Checkbox::CreateInkDrop() {
- // Completely removes the highlight.
std::unique_ptr<InkDropImpl> ink_drop = CreateDefaultInkDropImpl();
ink_drop->SetShowHighlightOnHover(false);
ink_drop->SetAutoHighlightMode(InkDropImpl::AutoHighlightMode::NONE);
@@ -117,12 +116,18 @@ std::unique_ptr<InkDrop> Checkbox::CreateInkDrop() {
std::unique_ptr<InkDropRipple> Checkbox::CreateInkDropRipple() const {
// The "small" size is 21dp, the large size is 1.33 * 21dp = 28dp.
- return CreateDefaultInkDropRipple(image()->GetMirroredBounds().CenterPoint(),
- gfx::Size(21, 21));
+ return CreateSquareInkDropRipple(image()->GetMirroredBounds().CenterPoint(),
+ gfx::Size(21, 21));
+}
+
+std::unique_ptr<InkDropMask> Checkbox::CreateInkDropMask() const {
+ // Avoid the default ink-drop mask to allow the ripple effect to extend beyond
+ // the checkbox view (otherwise it gets clipped which looks weird).
+ return nullptr;
}
SkColor Checkbox::GetInkDropBaseColor() const {
- // Usually ink drop ripples match the text color. Checkboxes use the color of
+ // Usually ink-drop ripples match the text color. Checkboxes use the color of
// the unchecked, enabled icon.
return GetIconImageColor(IconState::ENABLED);
}
@@ -161,17 +166,14 @@ const gfx::VectorIcon& Checkbox::GetVectorIcon() const {
}
SkColor Checkbox::GetIconImageColor(int icon_state) const {
- const SkColor active_color =
+ const SkColor active_color = GetNativeTheme()->GetSystemColor(
(icon_state & IconState::CHECKED)
- ? GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_ProminentButtonColor)
- // When unchecked, the icon color matches push button text color.
- : style::GetColor(*this, style::CONTEXT_BUTTON_MD,
- style::STYLE_PRIMARY);
+ ? ui::NativeTheme::kColorId_ProminentButtonColor
+ : ui::NativeTheme::kColorId_ButtonEnabledColor);
return (icon_state & IconState::ENABLED)
? active_color
- : color_utils::BlendTowardOppositeLuma(active_color,
- gfx::kDisabledControlAlpha);
+ : color_utils::BlendTowardMaxContrast(active_color,
+ gfx::kDisabledControlAlpha);
}
void Checkbox::NotifyClick(const ui::Event& event) {
diff --git a/chromium/ui/views/controls/button/checkbox.h b/chromium/ui/views/controls/button/checkbox.h
index d2b6f12e698..d6d9b2a20a1 100644
--- a/chromium/ui/views/controls/button/checkbox.h
+++ b/chromium/ui/views/controls/button/checkbox.h
@@ -52,6 +52,7 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
std::unique_ptr<InkDrop> CreateInkDrop() override;
std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override;
+ std::unique_ptr<InkDropMask> CreateInkDropMask() const override;
SkColor GetInkDropBaseColor() const override;
gfx::ImageSkia GetImage(ButtonState for_state) const override;
std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const override;
diff --git a/chromium/ui/views/controls/button/image_button.cc b/chromium/ui/views/controls/button/image_button.cc
index 851a2079c80..ca6b7a78e6b 100644
--- a/chromium/ui/views/controls/button/image_button.cc
+++ b/chromium/ui/views/controls/button/image_button.cc
@@ -33,7 +33,6 @@ ImageButton::ImageButton(ButtonListener* listener)
h_alignment_(ALIGN_LEFT),
v_alignment_(ALIGN_TOP),
draw_image_mirrored_(false) {
- SetFocusPainter(Painter::CreateDashedFocusPainter());
// By default, we request that the gfx::Canvas passed to our View::OnPaint()
// implementation is flipped horizontally so that the button's images are
// mirrored when the UI directionality is right-to-left.
diff --git a/chromium/ui/views/controls/button/image_button_factory.cc b/chromium/ui/views/controls/button/image_button_factory.cc
index 9932416dc82..30c082c307d 100644
--- a/chromium/ui/views/controls/button/image_button_factory.cc
+++ b/chromium/ui/views/controls/button/image_button_factory.cc
@@ -21,7 +21,6 @@ void ConfigureVectorImageButton(ImageButton* button) {
button->set_has_ink_drop_action_on_click(true);
button->SetImageAlignment(ImageButton::ALIGN_CENTER,
ImageButton::ALIGN_MIDDLE);
- button->SetFocusPainter(nullptr);
button->SetBorder(CreateEmptyBorder(
LayoutProvider::Get()->GetInsetsMetric(INSETS_VECTOR_IMAGE_BUTTON)));
}
@@ -53,6 +52,20 @@ void SetImageFromVectorIcon(ImageButton* button,
SkColor related_text_color) {
const SkColor icon_color =
color_utils::DeriveDefaultIconColor(related_text_color);
+ SetImageFromVectorIconWithColor(button, icon, dip_size, icon_color);
+}
+
+void SetImageFromVectorIconWithColor(ImageButton* button,
+ const gfx::VectorIcon& icon,
+ SkColor icon_color) {
+ SetImageFromVectorIconWithColor(button, icon,
+ GetDefaultSizeOfVectorIcon(icon), icon_color);
+}
+
+void SetImageFromVectorIconWithColor(ImageButton* button,
+ const gfx::VectorIcon& icon,
+ int dip_size,
+ SkColor icon_color) {
const SkColor disabled_color =
SkColorSetA(icon_color, gfx::kDisabledControlAlpha);
const gfx::ImageSkia& normal_image =
diff --git a/chromium/ui/views/controls/button/image_button_factory.h b/chromium/ui/views/controls/button/image_button_factory.h
index 0ce421eee68..0f407183132 100644
--- a/chromium/ui/views/controls/button/image_button_factory.h
+++ b/chromium/ui/views/controls/button/image_button_factory.h
@@ -45,6 +45,18 @@ VIEWS_EXPORT void SetImageFromVectorIcon(
int dip_size,
SkColor related_text_color = gfx::kGoogleGrey900);
+// Sets images on |button| for STATE_NORMAL and STATE_DISABLED from the given
+// vector icon and color.
+VIEWS_EXPORT void SetImageFromVectorIconWithColor(ImageButton* button,
+ const gfx::VectorIcon& icon,
+ SkColor icon_color);
+
+// As above, but creates the images at the given size.
+VIEWS_EXPORT void SetImageFromVectorIconWithColor(ImageButton* button,
+ const gfx::VectorIcon& icon,
+ int dip_size,
+ SkColor icon_color);
+
// As above, but sets the toggled images for a toggled image button.
VIEWS_EXPORT void SetToggledImageFromVectorIcon(
ToggleImageButton* button,
diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc
index 8fd404aa239..79b6dca3272 100644
--- a/chromium/ui/views/controls/button/label_button.cc
+++ b/chromium/ui/views/controls/button/label_button.cc
@@ -18,11 +18,7 @@
#include "ui/gfx/font_list.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/native_theme/native_theme.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"
-#include "ui/views/animation/square_ink_drop_ripple.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/controls/button/label_button_label.h"
@@ -75,9 +71,6 @@ LabelButton::LabelButton(ButtonListener* listener,
AddChildView(label_);
label_->SetAutoColorReadabilityEnabled(false);
label_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
-
- // Inset the button focus rect from the actual border; roughly match Windows.
- SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(gfx::Insets(3)));
}
LabelButton::~LabelButton() {}
@@ -345,10 +338,6 @@ gfx::Rect LabelButton::GetChildAreaBounds() {
return GetLocalBounds();
}
-bool LabelButton::ShouldUseFloodFillInkDrop() const {
- return !GetText().empty();
-}
-
void LabelButton::OnFocus() {
Button::OnFocus();
// Typically the border renders differently when focused.
@@ -385,39 +374,6 @@ void LabelButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
ink_drop_container_->RemoveInkDropLayer(ink_drop_layer);
}
-std::unique_ptr<InkDrop> LabelButton::CreateInkDrop() {
- return ShouldUseFloodFillInkDrop() ? CreateDefaultFloodFillInkDropImpl()
- : Button::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(),
- GetInkDropBaseColor(), ink_drop_visible_opacity())
- : CreateDefaultInkDropRipple(
- image()->GetMirroredBounds().CenterPoint());
-}
-
-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(),
- gfx::RectF(GetLocalBounds()).CenterPoint(),
- GetInkDropBaseColor())
- : CreateDefaultInkDropHighlight(
- gfx::RectF(image()->GetMirroredBounds()).CenterPoint());
-}
-
void LabelButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
if (is_default())
node_data->AddState(ax::mojom::State::kDefault);
diff --git a/chromium/ui/views/controls/button/label_button.h b/chromium/ui/views/controls/button/label_button.h
index 1a1ab365ad7..0200201196b 100644
--- a/chromium/ui/views/controls/button/label_button.h
+++ b/chromium/ui/views/controls/button/label_button.h
@@ -95,9 +95,6 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
void EnableCanvasFlippingForRTLUI(bool flip) override;
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;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
protected:
@@ -115,10 +112,6 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
// these bounds if they need room to do manual painting.
virtual gfx::Rect GetChildAreaBounds();
- // Returns true if the CreateInkDrop*() methods should create flood fill ink
- // drop components.
- virtual bool ShouldUseFloodFillInkDrop() const;
-
// View:
void OnFocus() override;
void OnBlur() override;
diff --git a/chromium/ui/views/controls/button/label_button_border.cc b/chromium/ui/views/controls/button/label_button_border.cc
index 7908d16fc50..8d663264ce6 100644
--- a/chromium/ui/views/controls/button/label_button_border.cc
+++ b/chromium/ui/views/controls/button/label_button_border.cc
@@ -149,7 +149,7 @@ void LabelButtonAssetBorder::Paint(const View& view, gfx::Canvas* canvas) {
{
// First, modulate the background by 1 - alpha.
cc::PaintCanvasAutoRestore auto_restore(canvas->sk_canvas(), false);
- canvas->sk_canvas()->saveLayerAlpha(&sk_rect, 255 - fg_alpha, false);
+ canvas->sk_canvas()->saveLayerAlpha(&sk_rect, 255 - fg_alpha);
state = native_theme_delegate->GetBackgroundThemeState(&extra);
PaintHelper(this, canvas, state, rect, extra);
}
diff --git a/chromium/ui/views/controls/button/md_text_button.cc b/chromium/ui/views/controls/button/md_text_button.cc
index c47cf87dcda..7f42ce4daab 100644
--- a/chromium/ui/views/controls/button/md_text_button.cc
+++ b/chromium/ui/views/controls/button/md_text_button.cc
@@ -75,10 +75,15 @@ void MdTextButton::set_corner_radius(float radius) {
void MdTextButton::OnPaintBackground(gfx::Canvas* canvas) {
LabelButton::OnPaintBackground(canvas);
if (hover_animation().is_animating() || state() == STATE_HOVERED) {
- const int kHoverAlpha = is_prominent_ ? 0x0c : 0x05;
- SkScalar alpha = hover_animation().CurrentValueBetween(0, kHoverAlpha);
+ bool is_dark_mode = GetNativeTheme()->SystemDarkModeEnabled();
+ int hover_alpha = is_prominent_ ? 0x0C : 0x05;
+ if (is_dark_mode)
+ hover_alpha = 0x0A;
+ const SkColor hover_color =
+ is_dark_mode && !is_prominent_ ? gfx::kGoogleBlue300 : SK_ColorBLACK;
+ SkScalar alpha = hover_animation().CurrentValueBetween(0, hover_alpha);
cc::PaintFlags flags;
- flags.setColor(SkColorSetA(SK_ColorBLACK, alpha));
+ flags.setColor(SkColorSetA(hover_color, alpha));
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setAntiAlias(true);
canvas->DrawRoundRect(gfx::RectF(GetLocalBounds()), corner_radius_, flags);
@@ -94,37 +99,38 @@ SkColor MdTextButton::GetInkDropBaseColor() const {
return color_utils::DeriveDefaultIconColor(label()->enabled_color());
}
-std::unique_ptr<InkDrop> MdTextButton::CreateInkDrop() {
- return CreateDefaultFloodFillInkDropImpl();
+void MdTextButton::StateChanged(ButtonState old_state) {
+ LabelButton::StateChanged(old_state);
+ UpdateColors();
}
-std::unique_ptr<views::InkDropRipple> MdTextButton::CreateInkDropRipple()
- const {
- return std::unique_ptr<views::InkDropRipple>(
- new views::FloodFillInkDropRipple(
- size(), GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(),
- ink_drop_visible_opacity()));
+void MdTextButton::OnFocus() {
+ LabelButton::OnFocus();
+ UpdateColors();
}
-void MdTextButton::StateChanged(ButtonState old_state) {
- LabelButton::StateChanged(old_state);
+void MdTextButton::OnBlur() {
+ LabelButton::OnBlur();
UpdateColors();
}
std::unique_ptr<views::InkDropHighlight> MdTextButton::CreateInkDropHighlight()
const {
+ bool is_dark_mode = GetNativeTheme()->SystemDarkModeEnabled();
// The prominent button hover effect is a shadow.
const int kYOffset = 1;
const int kSkiaBlurRadius = 2;
const int shadow_alpha = is_prominent_ ? 0x3D : 0x1A;
+ const SkColor shadow_color =
+ is_dark_mode && is_prominent_ ? gfx::kGoogleBlue300 : SK_ColorBLACK;
std::vector<gfx::ShadowValue> shadows;
// The notion of blur that gfx::ShadowValue uses is twice the Skia/CSS value.
// Skia counts the number of pixels outside the mask area whereas
// gfx::ShadowValue counts together the number of pixels inside and outside
// the mask bounds.
- shadows.push_back(gfx::ShadowValue(gfx::Vector2d(0, kYOffset),
- 2 * kSkiaBlurRadius,
- SkColorSetA(SK_ColorBLACK, shadow_alpha)));
+ shadows.push_back(gfx::ShadowValue(
+ gfx::Vector2d(0, kYOffset), 2 * kSkiaBlurRadius,
+ SkColorSetA(shadow_color, is_dark_mode ? 0x7F : shadow_alpha)));
const SkColor fill_color =
SkColorSetA(SK_ColorWHITE, is_prominent_ ? 0x0D : 0x05);
return std::make_unique<InkDropHighlight>(
@@ -159,7 +165,6 @@ MdTextButton::MdTextButton(ButtonListener* listener, int button_context)
const int minimum_width = LayoutProvider::Get()->GetDistanceMetric(
DISTANCE_DIALOG_BUTTON_MINIMUM_WIDTH);
SetMinSize(gfx::Size(minimum_width, 0));
- SetFocusPainter(nullptr);
SetInstallFocusRingOnFocus(true);
label()->SetAutoColorReadabilityEnabled(false);
set_request_focus_on_press(false);
@@ -222,11 +227,11 @@ void MdTextButton::UpdateColors() {
if (!explicitly_set_normal_color()) {
const auto colors = explicitly_set_colors();
LabelButton::SetEnabledTextColors(enabled_text_color);
- // Non-prominent, disabled buttons need the disabled color explicitly set.
+ // Disabled buttons need the disabled color explicitly set.
// This ensures that label()->enabled_color() returns the correct color as
// the basis for calculating the stroke color. enabled_text_color isn't used
// since a descendant could have overridden the label enabled color.
- if (is_disabled && !is_prominent_) {
+ if (is_disabled) {
LabelButton::SetTextColor(STATE_DISABLED,
style::GetColor(*this, label()->text_context(),
style::STYLE_DISABLED));
@@ -234,13 +239,7 @@ void MdTextButton::UpdateColors() {
set_explicitly_set_colors(colors);
}
- // Prominent buttons keep their enabled text color; disabled state is conveyed
- // by shading the background instead.
- if (is_prominent_)
- SetTextColor(STATE_DISABLED, enabled_text_color);
-
ui::NativeTheme* theme = GetNativeTheme();
- SkColor text_color = label()->enabled_color();
SkColor bg_color =
theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground);
@@ -248,10 +247,11 @@ void MdTextButton::UpdateColors() {
bg_color = *bg_color_override_;
} else if (is_prominent_) {
bg_color = theme->GetSystemColor(
- ui::NativeTheme::kColorId_ProminentButtonColor);
+ HasFocus() ? ui::NativeTheme::kColorId_ProminentButtonFocusedColor
+ : ui::NativeTheme::kColorId_ProminentButtonColor);
if (is_disabled) {
- bg_color = color_utils::BlendTowardOppositeLuma(
- bg_color, gfx::kDisabledControlAlpha);
+ bg_color = theme->GetSystemColor(
+ ui::NativeTheme::kColorId_ProminentButtonDisabledColor);
}
}
@@ -265,25 +265,11 @@ void MdTextButton::UpdateColors() {
if (is_prominent_) {
stroke_color = SK_ColorTRANSPARENT;
} else {
- int stroke_alpha;
- if (is_disabled) {
- // Disabled, non-prominent buttons need a lighter stroke. This alpha
- // value will take the disabled button colors, a1a192 @ 1.0 alpha for
- // non-Harmony, 9e9e9e @ 1.0 alpha for Harmony and turn it into
- // e6e6e6 @ 1.0 alpha (or very close to it) or an effective 000000 @ 0.1
- // alpha for the stroke color. The same alpha value will work with both
- // Harmony and non-Harmony colors.
- stroke_alpha = 0x43;
- } else {
- // These alpha values will take the enabled button colors, 757575 @ 1.0
- // alpha turn it into an effective b2b2b2 @ 1.0 alpha or 000000 @ 0.3 for
- // the stroke_color.
- stroke_alpha = 0x8f;
- }
- stroke_color = SkColorSetA(text_color, stroke_alpha);
+ stroke_color = SkColorSetA(
+ theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonBorderColor),
+ is_disabled ? 0x43 : SK_AlphaOPAQUE);
}
- DCHECK_EQ(SK_AlphaOPAQUE, static_cast<int>(SkColorGetA(bg_color)));
SetBackground(
CreateBackgroundFromPainter(Painter::CreateRoundRectWith1PxBorderPainter(
bg_color, stroke_color, corner_radius_)));
diff --git a/chromium/ui/views/controls/button/md_text_button.h b/chromium/ui/views/controls/button/md_text_button.h
index eafa8a817ba..bfd98baa805 100644
--- a/chromium/ui/views/controls/button/md_text_button.h
+++ b/chromium/ui/views/controls/button/md_text_button.h
@@ -39,13 +39,8 @@ class VIEWS_EXPORT MdTextButton : public LabelButton {
// background and ink drop effects.
void set_corner_radius(float radius);
- // View:
- void OnPaintBackground(gfx::Canvas* canvas) override;
-
// LabelButton:
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
- std::unique_ptr<InkDrop> CreateInkDrop() override;
- std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
const override;
SkColor GetInkDropBaseColor() const override;
@@ -55,6 +50,11 @@ class VIEWS_EXPORT MdTextButton : public LabelButton {
void StateChanged(ButtonState old_state) override;
protected:
+ // View:
+ void OnPaintBackground(gfx::Canvas* canvas) override;
+ void OnFocus() override;
+ void OnBlur() override;
+
MdTextButton(ButtonListener* listener, int button_context);
private:
diff --git a/chromium/ui/views/controls/button/menu_button_unittest.cc b/chromium/ui/views/controls/button/menu_button_unittest.cc
index 823940021dc..f310447a975 100644
--- a/chromium/ui/views/controls/button/menu_button_unittest.cc
+++ b/chromium/ui/views/controls/button/menu_button_unittest.cc
@@ -384,12 +384,6 @@ TEST_F(MenuButtonTest, InkDropCenterSetFromClickWithPressedLock) {
// Test that the MenuButton stays pressed while there are any PressedLocks.
TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) {
- // Similarly for aura-mus-client the location of the cursor is not updated by
- // EventGenerator so that IsMouseHovered() checks the wrong thing.
- // https://crbug.com/615033.
- if (IsMus())
- return;
-
CreateMenuButtonWithNoListener();
// Move the mouse over the button; the button should be in a hovered state.
@@ -578,10 +572,6 @@ TEST_F(MenuButtonTest,
// Tests that the MenuButton does not become pressed if it can be dragged, and a
// DragDropClient is processing the events.
TEST_F(MenuButtonTest, DraggableMenuButtonDoesNotActivateOnDrag) {
- // TODO(https://crbug.com/663809): test uses GetContext(), which is not
- // applicable to aura-mus.
- if (IsMus())
- return;
TestMenuButtonListener menu_button_listener;
CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
TestDragController drag_controller;
@@ -606,11 +596,6 @@ TEST_F(MenuButtonTest, DraggableMenuButtonDoesNotActivateOnDrag) {
// Tests if the listener is notified correctly when a gesture tap happens on a
// MenuButton that has a MenuButtonListener.
TEST_F(MenuButtonTest, ActivateDropDownOnGestureTap) {
- // Similarly for aura-mus-client the location of the cursor is not updated by
- // EventGenerator so that IsMouseHovered() checks the wrong thing.
- // https://crbug.com/615033.
- if (IsMus())
- return;
TestMenuButtonListener menu_button_listener;
CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
diff --git a/chromium/ui/views/controls/button/radio_button.cc b/chromium/ui/views/controls/button/radio_button.cc
index 6113742ab7f..05cb8afea41 100644
--- a/chromium/ui/views/controls/button/radio_button.cc
+++ b/chromium/ui/views/controls/button/radio_button.cc
@@ -38,7 +38,7 @@ void RadioButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
View* RadioButton::GetSelectedViewForGroup(int group) {
Views views;
- GetWidget()->GetRootView()->GetViewsInGroup(group, &views);
+ GetViewsInGroupFromParent(group, &views);
if (views.empty())
return NULL;
@@ -66,7 +66,7 @@ void RadioButton::RequestFocusFromEvent() {
Checkbox::RequestFocusFromEvent();
// Take focus only if another radio button in the group has focus.
Views views;
- GetWidget()->GetRootView()->GetViewsInGroup(GetGroup(), &views);
+ GetViewsInGroupFromParent(GetGroup(), &views);
if (std::find_if(views.begin(), views.end(), [](View* v) -> bool {
return v->HasFocus();
}) != views.end()) {
@@ -90,25 +90,20 @@ void RadioButton::SetChecked(bool checked) {
if (checked == RadioButton::checked())
return;
if (checked) {
- // We can't just get the root view here because sometimes the radio
- // button isn't attached to a root view (e.g., if it's part of a tab page
- // that is currently not active).
- View* container = parent();
- while (container && container->parent())
- container = container->parent();
- if (container) {
- Views other;
- container->GetViewsInGroup(GetGroup(), &other);
- for (auto i(other.begin()); i != other.end(); ++i) {
- if (*i != this) {
- if (strcmp((*i)->GetClassName(), kViewClassName)) {
- NOTREACHED() << "radio-button-nt has same group as other non "
- "radio-button-nt views.";
- continue;
- }
- RadioButton* peer = static_cast<RadioButton*>(*i);
- peer->SetChecked(false);
+ // We can't start from the root view because other parts of the UI might use
+ // radio buttons with the same group. This can happen when re-using the same
+ // component or even if views want to use the group for a different purpose.
+ Views other;
+ GetViewsInGroupFromParent(GetGroup(), &other);
+ for (auto i(other.begin()); i != other.end(); ++i) {
+ if (*i != this) {
+ if (strcmp((*i)->GetClassName(), kViewClassName)) {
+ NOTREACHED() << "radio-button-nt has same group as other non "
+ "radio-button-nt views.";
+ continue;
}
+ RadioButton* peer = static_cast<RadioButton*>(*i);
+ peer->SetChecked(false);
}
}
}
@@ -125,4 +120,10 @@ SkPath RadioButton::GetFocusRingPath() const {
return path;
}
+void RadioButton::GetViewsInGroupFromParent(int group, Views* views) {
+ if (!parent())
+ return;
+ parent()->GetViewsInGroup(group, views);
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/button/radio_button.h b/chromium/ui/views/controls/button/radio_button.h
index 2810468881f..eda57860d3c 100644
--- a/chromium/ui/views/controls/button/radio_button.h
+++ b/chromium/ui/views/controls/button/radio_button.h
@@ -42,6 +42,8 @@ class VIEWS_EXPORT RadioButton : public Checkbox {
SkPath GetFocusRingPath() const override;
private:
+ void GetViewsInGroupFromParent(int group, Views* views);
+
DISALLOW_COPY_AND_ASSIGN(RadioButton);
};
diff --git a/chromium/ui/views/controls/button/toggle_button.cc b/chromium/ui/views/controls/button/toggle_button.cc
index 650d85b8c34..69cb2036f6a 100644
--- a/chromium/ui/views/controls/button/toggle_button.cc
+++ b/chromium/ui/views/controls/button/toggle_button.cc
@@ -36,10 +36,10 @@ constexpr int kThumbInset = 2;
// Class representing the thumb (the circle that slides horizontally).
class ToggleButton::ThumbView : public InkDropHostView {
public:
- ThumbView() : color_ratio_(0.) {}
+ ThumbView() : color_ratio_(0.0f) {}
~ThumbView() override {}
- void Update(const gfx::Rect& bounds, double color_ratio) {
+ void Update(const gfx::Rect& bounds, float color_ratio) {
SetBoundsRect(bounds);
color_ratio_ = color_ratio;
SchedulePaint();
@@ -85,9 +85,8 @@ class ToggleButton::ThumbView : public InkDropHostView {
ui::NativeTheme::kColorId_ProminentButtonColor);
const SkColor thumb_off_color = GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_DialogBackground);
- const SkAlpha blend = static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio_);
thumb_flags.setColor(
- color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend));
+ color_utils::AlphaBlend(thumb_on_color, thumb_off_color, color_ratio_));
// We want the circle to have an integer pixel diameter and to be aligned
// with pixel boundaries, so we scale dip bounds to pixel bounds and round.
@@ -101,7 +100,7 @@ class ToggleButton::ThumbView : public InkDropHostView {
}
// Color ratio between 0 and 1 that controls the thumb color.
- double color_ratio_;
+ float color_ratio_;
DISALLOW_COPY_AND_ASSIGN(ThumbView);
};
@@ -167,7 +166,8 @@ gfx::Rect ToggleButton::GetThumbBounds() const {
}
void ToggleButton::UpdateThumb() {
- thumb_view_->Update(GetThumbBounds(), slide_animation_.GetCurrentValue());
+ thumb_view_->Update(GetThumbBounds(),
+ static_cast<float>(slide_animation_.GetCurrentValue()));
}
SkColor ToggleButton::GetTrackColor(bool is_on) const {
@@ -240,10 +240,10 @@ void ToggleButton::PaintButtonContents(gfx::Canvas* canvas) {
track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect));
cc::PaintFlags track_flags;
track_flags.setAntiAlias(true);
- const double color_ratio = slide_animation_.GetCurrentValue();
+ const float color_ratio =
+ static_cast<float>(slide_animation_.GetCurrentValue());
track_flags.setColor(color_utils::AlphaBlend(
- GetTrackColor(true), GetTrackColor(false),
- static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio)));
+ GetTrackColor(true), GetTrackColor(false), color_ratio));
canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_flags);
canvas->Restore();
}
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc
index 41a5ac2b1b3..defdcf540cf 100644
--- a/chromium/ui/views/controls/combobox/combobox.cc
+++ b/chromium/ui/views/controls/combobox/combobox.cc
@@ -41,9 +41,11 @@ namespace {
constexpr int kNoSelection = -1;
SkColor GetTextColorForEnableState(const Combobox& combobox, bool enabled) {
- return style::GetColor(
- combobox, style::CONTEXT_TEXTFIELD,
- enabled ? style::STYLE_PRIMARY : style::STYLE_DISABLED);
+ SkColor color =
+ style::GetColor(combobox, style::CONTEXT_TEXTFIELD, style::STYLE_PRIMARY);
+ if (!enabled)
+ color = SkColorSetA(color, gfx::kDisabledControlAlpha);
+ return color;
}
// The transparent button which holds a button state but is not rendered.
@@ -161,7 +163,7 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel,
bool IsItemDynamicAt(int index) const override { return true; }
const gfx::FontList* GetLabelFontListAt(int index) const override {
- return &GetFontList();
+ return &owner_->GetFontList();
}
bool GetAcceleratorAt(int index,
@@ -185,8 +187,6 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel,
return model_->IsItemEnabledAt(index);
}
- void HighlightChangedTo(int index) override {}
-
void ActivatedAt(int index) override {
owner_->selected_index_ = index;
owner_->OnPerformAction();
@@ -217,13 +217,17 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel,
////////////////////////////////////////////////////////////////////////////////
// Combobox, public:
-Combobox::Combobox(std::unique_ptr<ui::ComboboxModel> model)
- : Combobox(model.get()) {
+Combobox::Combobox(std::unique_ptr<ui::ComboboxModel> model,
+ int text_context,
+ int text_style)
+ : Combobox(model.get(), text_context, text_style) {
owned_model_ = std::move(model);
}
-Combobox::Combobox(ui::ComboboxModel* model)
+Combobox::Combobox(ui::ComboboxModel* model, int text_context, int text_style)
: model_(model),
+ text_context_(text_context),
+ text_style_(text_style),
listener_(nullptr),
selected_index_(model_->GetDefaultIndex()),
invalid_(false),
@@ -257,9 +261,8 @@ Combobox::~Combobox() {
}
}
-// static
-const gfx::FontList& Combobox::GetFontList() {
- return style::GetFont(style::CONTEXT_BUTTON, style::STYLE_PRIMARY);
+const gfx::FontList& Combobox::GetFontList() const {
+ return style::GetFont(text_context_, text_style_);
}
void Combobox::ModelChanged() {
@@ -521,7 +524,7 @@ void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
// 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_;
+ const base::TimeDelta delta = base::TimeTicks::Now() - closed_time_;
if (delta.InMilliseconds() <= kMinimumMsBetweenButtonClicks)
return;
@@ -564,7 +567,7 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
int disclosure_arrow_offset = width() - GetArrowContainerWidth();
- const gfx::FontList& font_list = Combobox::GetFontList();
+ const gfx::FontList& font_list = GetFontList();
int text_width = gfx::GetStringWidth(text, font_list);
if ((text_width + insets.width()) > disclosure_arrow_offset)
text_width = disclosure_arrow_offset - insets.width();
@@ -597,10 +600,7 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
path.rLineTo(height, -height);
path.close();
cc::PaintFlags flags;
- SkColor arrow_color = GetTextColorForEnableState(*this, true);
- if (!enabled())
- arrow_color = SkColorSetA(arrow_color, gfx::kDisabledControlAlpha);
- flags.setColor(arrow_color);
+ flags.setColor(text_color);
flags.setAntiAlias(true);
canvas->DrawPath(path, flags);
}
@@ -644,7 +644,7 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
void Combobox::OnMenuClosed(Button::ButtonState original_button_state) {
menu_runner_.reset();
arrow_button_->SetState(original_button_state);
- closed_time_ = base::Time::Now();
+ closed_time_ = base::TimeTicks::Now();
}
void Combobox::OnPerformAction() {
diff --git a/chromium/ui/views/controls/combobox/combobox.h b/chromium/ui/views/controls/combobox/combobox.h
index 9f86b4619e5..ec4fb68f6c1 100644
--- a/chromium/ui/views/controls/combobox/combobox.h
+++ b/chromium/ui/views/controls/combobox/combobox.h
@@ -10,6 +10,7 @@
#include "base/time/time.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/prefix_delegate.h"
+#include "ui/views/style/typography.h"
namespace gfx {
class FontList;
@@ -38,14 +39,20 @@ class VIEWS_EXPORT Combobox : public View,
public:
// The combobox's class name.
static const char kViewClassName[];
+ static const int kDefaultComboboxTextContext = style::CONTEXT_BUTTON;
+ static const int kDefaultComboboxTextStyle = style::STYLE_PRIMARY;
// |model| is owned by the combobox when using this constructor.
- explicit Combobox(std::unique_ptr<ui::ComboboxModel> model);
+ explicit Combobox(std::unique_ptr<ui::ComboboxModel> model,
+ int text_context = kDefaultComboboxTextContext,
+ int text_style = kDefaultComboboxTextStyle);
// |model| is not owned by the combobox when using this constructor.
- explicit Combobox(ui::ComboboxModel* model);
+ explicit Combobox(ui::ComboboxModel* model,
+ int text_context = kDefaultComboboxTextContext,
+ int text_style = kDefaultComboboxTextStyle);
~Combobox() override;
- static const gfx::FontList& GetFontList();
+ const gfx::FontList& GetFontList() const;
// Sets the listener which will be called when a selection has been made.
void set_listener(ComboboxListener* listener) { listener_ = listener; }
@@ -149,6 +156,14 @@ class VIEWS_EXPORT Combobox : public View,
// Reference to our model, which may be owned or not.
ui::ComboboxModel* model_;
+ // Typography context for the text written in the combobox and the options
+ // shown in the drop-down menu.
+ const int text_context_;
+
+ // Typography style for the text written in the combobox and the options shown
+ // in the drop-down menu.
+ const int text_style_;
+
// Our listener. Not owned. Notified when the selected index change.
ComboboxListener* listener_;
@@ -173,7 +188,7 @@ class VIEWS_EXPORT Combobox : public View,
// 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::Time closed_time_;
+ base::TimeTicks closed_time_;
// The maximum dimensions of the content in the dropdown.
gfx::Size content_size_;
diff --git a/chromium/ui/views/controls/focus_ring.cc b/chromium/ui/views/controls/focus_ring.cc
index f5fbb33ec88..942cecbe60e 100644
--- a/chromium/ui/views/controls/focus_ring.cc
+++ b/chromium/ui/views/controls/focus_ring.cc
@@ -9,6 +9,8 @@
#include "ui/views/style/platform_style.h"
#include "ui/views/view_properties.h"
+namespace views {
+
namespace {
ui::NativeTheme::ColorId ColorIdForValidity(bool valid) {
@@ -16,9 +18,12 @@ ui::NativeTheme::ColorId ColorIdForValidity(bool valid) {
: ui::NativeTheme::kColorId_AlertSeverityHigh;
}
-} // namespace
+double GetCornerRadius() {
+ double thickness = PlatformStyle::kFocusHaloThickness / 2.f;
+ return FocusableBorder::kCornerRadiusDp + thickness;
+}
-namespace views {
+} // namespace
const char FocusRing::kViewClassName[] = "FocusRing";
@@ -54,6 +59,11 @@ void FocusRing::SetHasFocusPredicate(const ViewPredicate& predicate) {
SchedulePaint();
}
+void FocusRing::SetColor(base::Optional<SkColor> color) {
+ color_ = color;
+ SchedulePaint();
+}
+
const char* FocusRing::GetClassName() const {
return kViewClassName;
}
@@ -70,23 +80,16 @@ void FocusRing::OnPaint(gfx::Canvas* canvas) {
if (!has_focus_predicate_(parent()))
return;
- SkColor base_color =
- GetNativeTheme()->GetSystemColor(ColorIdForValidity(!invalid_));
-
cc::PaintFlags paint;
paint.setAntiAlias(true);
- paint.setColor(SkColorSetA(base_color, 0x66));
+ paint.setColor(color_.value_or(SkColorSetA(
+ GetNativeTheme()->GetSystemColor(ColorIdForValidity(!invalid_)), 0x66)));
paint.setStyle(cc::PaintFlags::kStroke_Style);
paint.setStrokeWidth(PlatformStyle::kFocusHaloThickness);
SkPath path = path_;
- if (path.isEmpty()) {
- SkPath* highlight_path = parent()->GetProperty(kHighlightPathKey);
- if (highlight_path)
- path = *highlight_path;
- }
if (path.isEmpty())
- path.addRect(RectToSkRect(parent()->GetLocalBounds()));
+ path = GetHighlightPath(parent());
DCHECK(IsPathUseable(path));
SkRect bounds;
@@ -127,8 +130,7 @@ FocusRing::~FocusRing() {
}
SkRRect FocusRing::RingRectFromPathRect(const SkRect& rect) const {
- double thickness = PlatformStyle::kFocusHaloThickness / 2.f;
- double corner_radius = FocusableBorder::kCornerRadiusDp + thickness;
+ const double corner_radius = GetCornerRadius();
return RingRectFromPathRect(
SkRRect::MakeRectXY(rect, corner_radius, corner_radius));
}
@@ -150,4 +152,16 @@ SkRRect FocusRing::RingRectFromPathRect(const SkRRect& rrect) const {
return skr;
}
+SkPath GetHighlightPath(const View* view) {
+ SkPath* highlight_path = view->GetProperty(kHighlightPathKey);
+ if (highlight_path)
+ return *highlight_path;
+
+ const double corner_radius = GetCornerRadius();
+ SkPath path;
+ path.addRRect(SkRRect::MakeRectXY(RectToSkRect(view->GetLocalBounds()),
+ corner_radius, corner_radius));
+ return path;
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/focus_ring.h b/chromium/ui/views/controls/focus_ring.h
index 1627eda9347..d356c773a73 100644
--- a/chromium/ui/views/controls/focus_ring.h
+++ b/chromium/ui/views/controls/focus_ring.h
@@ -74,6 +74,8 @@ class VIEWS_EXPORT FocusRing : public View, public ViewObserver {
// focus, but the FocusRing sits on the parent instead of the inner view.
void SetHasFocusPredicate(const ViewPredicate& predicate);
+ void SetColor(base::Optional<SkColor> color);
+
// View:
const char* GetClassName() const override;
void Layout() override;
@@ -105,12 +107,17 @@ class VIEWS_EXPORT FocusRing : public View, public ViewObserver {
// the focus ring shows an invalid appearance (usually a different color).
bool invalid_ = false;
+ // Overriding color for the focus ring.
+ base::Optional<SkColor> color_;
+
// The predicate used to determine whether the parent has focus.
ViewPredicate has_focus_predicate_;
DISALLOW_COPY_AND_ASSIGN(FocusRing);
};
+VIEWS_EXPORT SkPath GetHighlightPath(const View* view);
+
} // views
#endif // UI_VIEWS_CONTROLS_FOCUS_RING_H_
diff --git a/chromium/ui/views/controls/focusable_border.cc b/chromium/ui/views/controls/focusable_border.cc
index 800736a15d0..82eab4bad1f 100644
--- a/chromium/ui/views/controls/focusable_border.cc
+++ b/chromium/ui/views/controls/focusable_border.cc
@@ -81,11 +81,9 @@ SkColor FocusableBorder::GetCurrentColor(const View& view) const {
color_id = *override_color_id_;
SkColor color = view.GetNativeTheme()->GetSystemColor(color_id);
- if (!view.enabled()) {
- return color_utils::BlendTowardOppositeLuma(color,
- gfx::kDisabledControlAlpha);
- }
- return color;
+ return view.enabled() ? color
+ : color_utils::BlendTowardMaxContrast(
+ color, gfx::kDisabledControlAlpha);
}
} // namespace views
diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc
index b5baab3cbb1..ef1ed1092eb 100644
--- a/chromium/ui/views/controls/label.cc
+++ b/chromium/ui/views/controls/label.cc
@@ -33,16 +33,16 @@
#include "ui/views/native_cursor.h"
#include "ui/views/selection_controller.h"
-namespace views {
namespace {
-// Returns additional Insets applied to |label->GetContentsBounds()| to obtain
-// the text bounds. GetContentsBounds() includes the Border, but not any
-// additional insets used by the Label (e.g. for a focus ring).
-gfx::Insets NonBorderInsets(const Label& label) {
- return label.GetInsets() - label.View::GetInsets();
+
+bool IsOpaque(SkColor color) {
+ return SkColorGetA(color) == SK_AlphaOPAQUE;
}
+
} // namespace
+namespace views {
+
const char Label::kViewClassName[] = "Label";
Label::Label() : Label(base::string16()) {
@@ -449,20 +449,14 @@ void Label::PaintFocusRing(gfx::Canvas* canvas) const {
// No focus ring by default.
}
-gfx::Rect Label::GetFocusRingBounds() const {
+gfx::Rect Label::GetTextBounds() const {
MaybeBuildDisplayText();
- gfx::Rect focus_bounds;
- if (!display_text_) {
- focus_bounds = gfx::Rect(GetTextSize());
- } else {
- focus_bounds = gfx::Rect(gfx::Point() + display_text_->GetLineOffset(0),
- display_text_->GetStringSize());
- }
+ if (!display_text_)
+ return gfx::Rect(GetTextSize());
- focus_bounds.Inset(-NonBorderInsets(*this));
- focus_bounds.Intersect(GetLocalBounds());
- return focus_bounds;
+ return gfx::Rect(gfx::Point() + display_text_->GetLineOffset(0),
+ display_text_->GetStringSize());
}
void Label::PaintText(gfx::Canvas* canvas) {
@@ -479,8 +473,7 @@ void Label::PaintText(gfx::Canvas* canvas) {
return;
for (View* view = this; view; view = view->parent()) {
- if (view->background() &&
- SkColorGetA(view->background()->get_color()) == SK_AlphaOPAQUE)
+ if (view->background() && IsOpaque(view->background()->get_color()))
break;
if (view->layer() && view->layer()->fills_bounds_opaquely()) {
@@ -845,7 +838,6 @@ void Label::MaybeBuildDisplayText() const {
return;
gfx::Rect rect = GetContentsBounds();
- rect.Inset(NonBorderInsets(*this));
if (rect.IsEmpty())
return;
@@ -875,16 +867,23 @@ gfx::Size Label::GetTextSize() const {
return size;
}
+SkColor Label::GetForegroundColor(SkColor foreground,
+ SkColor background) const {
+ return (auto_color_readability_ && IsOpaque(background))
+ ? color_utils::GetColorWithMinimumContrast(foreground, background)
+ : foreground;
+}
+
void Label::RecalculateColors() {
- actual_enabled_color_ = auto_color_readability_ ?
- color_utils::GetReadableColor(requested_enabled_color_,
- background_color_) :
- requested_enabled_color_;
+ actual_enabled_color_ =
+ GetForegroundColor(requested_enabled_color_, background_color_);
+ // Using GetResultingPaintColor() here allows non-opaque selection backgrounds
+ // to still participate in auto color readability, assuming
+ // |background_color_| is itself opaque.
actual_selection_text_color_ =
- auto_color_readability_
- ? color_utils::GetReadableColor(requested_selection_text_color_,
- selection_background_color_)
- : requested_selection_text_color_;
+ GetForegroundColor(requested_selection_text_color_,
+ color_utils::GetResultingPaintColor(
+ selection_background_color_, background_color_));
ApplyTextColors();
SchedulePaint();
@@ -894,15 +893,13 @@ void Label::ApplyTextColors() const {
if (!display_text_)
return;
- bool subpixel_rendering_suppressed =
- SkColorGetA(background_color_) != SK_AlphaOPAQUE ||
- !subpixel_rendering_enabled_;
display_text_->SetColor(actual_enabled_color_);
display_text_->set_selection_color(actual_selection_text_color_);
display_text_->set_selection_background_focused_color(
selection_background_color_);
- display_text_->set_subpixel_rendering_suppressed(
- subpixel_rendering_suppressed);
+ const bool subpixel_rendering_enabled =
+ subpixel_rendering_enabled_ && IsOpaque(background_color_);
+ display_text_->set_subpixel_rendering_suppressed(!subpixel_rendering_enabled);
}
void Label::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h
index 9c78b30ab3a..771034ccebb 100644
--- a/chromium/ui/views/controls/label.h
+++ b/chromium/ui/views/controls/label.h
@@ -81,8 +81,9 @@ class VIEWS_EXPORT Label : public View,
// Enables or disables auto-color-readability (enabled by default). If this
// is enabled, then calls to set any foreground or background color will
- // trigger an automatic mapper that uses color_utils::GetReadableColor() to
- // ensure that the foreground colors are readable over the background color.
+ // trigger an automatic mapper that uses
+ // color_utils::GetColorWithMinimumContrast() to ensure that the foreground
+ // colors are readable over the background color.
void SetAutoColorReadabilityEnabled(bool enabled);
// Sets the color. This will automatically force the color to be readable
@@ -231,7 +232,10 @@ class VIEWS_EXPORT Label : public View,
// Draw a focus ring. The default implementation does nothing.
virtual void PaintFocusRing(gfx::Canvas* canvas) const;
- gfx::Rect GetFocusRingBounds() const;
+
+ // Returns the preferred size and position of the text in local coordinates,
+ // which may exceed the local bounds of the label.
+ gfx::Rect GetTextBounds() const;
void PaintText(gfx::Canvas* canvas);
@@ -308,6 +312,10 @@ class VIEWS_EXPORT Label : public View,
// Get the text size for the current layout.
gfx::Size GetTextSize() const;
+ // Returns the appropriate foreground color to use given the proposed
+ // |foreground| and |background| colors.
+ SkColor GetForegroundColor(SkColor foreground, SkColor background) const;
+
// Updates text and selection colors from requested colors.
void RecalculateColors();
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index aec4a0a0d3d..f6b1ccc5ca0 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -6,6 +6,9 @@
#include <stddef.h>
+#include <string>
+#include <vector>
+
#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/strings/utf_string_conversions.h"
@@ -891,84 +894,15 @@ TEST_F(LabelTest, NoSchedulePaintInOnPaint) {
EXPECT_EQ(count, label.schedule_paint_count()); // Unchanged.
}
-TEST_F(LabelTest, FocusBounds) {
- label()->SetText(ASCIIToUTF16("Example"));
- Link concrete_link(ASCIIToUTF16("Example"));
- Label* link = &concrete_link; // Allow LabelTest to call methods as friend.
- link->SetFocusBehavior(View::FocusBehavior::NEVER);
-
- label()->SizeToPreferredSize();
- link->SizeToPreferredSize();
-
- // A regular label never draws a focus ring, so it should exactly match the
- // font height (assuming no glyphs came from fallback fonts).
- EXPECT_EQ(label()->font_list().GetHeight(),
- label()->GetFocusRingBounds().height());
-
- // The test starts by setting the link unfocusable, so it should also match.
- EXPECT_EQ(link->font_list().GetHeight(), link->GetFocusRingBounds().height());
-
- // Labels are not focusable unless they are links, so don't change size when
- // the focus behavior changes.
- gfx::Size normal_label_size = label()->GetPreferredSize();
- label()->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- EXPECT_EQ(normal_label_size, label()->GetPreferredSize());
-
- gfx::Size normal_link_size = link->GetPreferredSize();
- link->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- gfx::Size focusable_link_size = link->GetPreferredSize();
-
- // Everything should match since underlines indicates focus.
- EXPECT_EQ(normal_label_size, normal_link_size);
- EXPECT_EQ(normal_link_size, focusable_link_size);
-
- // Requesting focus doesn't change the preferred size since that would mess up
- // layout.
- label()->RequestFocus();
- EXPECT_EQ(focusable_link_size, link->GetPreferredSize());
-
- label()->SizeToPreferredSize();
- gfx::Rect focus_bounds = label()->GetFocusRingBounds();
- EXPECT_EQ(label()->GetLocalBounds(), focus_bounds);
-
- gfx::Size focusable_size = normal_label_size;
- label()->SetBounds(
- 0, 0, focusable_size.width() * 2, focusable_size.height() * 2);
- label()->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- focus_bounds = label()->GetFocusRingBounds();
- EXPECT_EQ(0, focus_bounds.x());
- EXPECT_LT(0, focus_bounds.y());
- EXPECT_GT(label()->bounds().bottom(), focus_bounds.bottom());
- EXPECT_EQ(focusable_size, focus_bounds.size());
-
- label()->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
- focus_bounds = label()->GetFocusRingBounds();
- EXPECT_LT(0, focus_bounds.x());
- EXPECT_EQ(label()->bounds().right(), focus_bounds.right());
- EXPECT_LT(0, focus_bounds.y());
- EXPECT_GT(label()->bounds().bottom(), focus_bounds.bottom());
- EXPECT_EQ(focusable_size, focus_bounds.size());
-
- label()->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- label()->SetElideBehavior(gfx::FADE_TAIL);
- label()->SetBounds(0, 0, focusable_size.width() / 2, focusable_size.height());
- focus_bounds = label()->GetFocusRingBounds();
- EXPECT_EQ(0, focus_bounds.x());
- EXPECT_EQ(focusable_size.width() / 2, focus_bounds.width());
-}
-
TEST_F(LabelTest, EmptyLabel) {
label()->SetFocusBehavior(View::FocusBehavior::ALWAYS);
label()->RequestFocus();
label()->SizeToPreferredSize();
+ EXPECT_TRUE(label()->size().IsEmpty());
+ // With no text, neither links nor labels have a size in any dimension.
Link concrete_link((base::string16()));
- Label* link = &concrete_link; // Allow LabelTest to call methods as friend.
-
- // With no text, neither links nor labels are focusable, and have no size in
- // any dimension.
- EXPECT_EQ(gfx::Rect(), label()->GetFocusRingBounds());
- EXPECT_EQ(gfx::Rect(), link->GetFocusRingBounds());
+ EXPECT_TRUE(concrete_link.GetPreferredSize().IsEmpty());
}
TEST_F(LabelSelectionTest, Selectable) {
diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc
index e47a0c89edb..b18b5a3dfae 100644
--- a/chromium/ui/views/controls/link.cc
+++ b/chromium/ui/views/controls/link.cc
@@ -50,8 +50,12 @@ Link::FocusStyle Link::GetFocusStyle() const {
}
void Link::PaintFocusRing(gfx::Canvas* canvas) const {
- if (GetFocusStyle() == FocusStyle::RING)
- canvas->DrawFocusRect(GetFocusRingBounds());
+ if (GetFocusStyle() == FocusStyle::RING) {
+ gfx::Rect focus_ring_bounds = GetTextBounds();
+ focus_ring_bounds.Inset(gfx::Insets(-kFocusBorderPadding));
+ focus_ring_bounds.Intersect(GetLocalBounds());
+ canvas->DrawFocusRect(focus_ring_bounds);
+ }
}
gfx::Insets Link::GetInsets() const {
diff --git a/chromium/ui/views/controls/menu/menu_config.cc b/chromium/ui/views/controls/menu/menu_config.cc
index 3dc6eef0d4f..d45ea5773b2 100644
--- a/chromium/ui/views/controls/menu/menu_config.cc
+++ b/chromium/ui/views/controls/menu/menu_config.cc
@@ -70,7 +70,8 @@ MenuConfig::MenuConfig()
padded_separator_left_margin(64),
arrow_key_selection_wraps(true),
show_context_menu_accelerators(true),
- all_menus_use_prefix_selection(false) {
+ all_menus_use_prefix_selection(false),
+ footnote_vertical_margin(11) {
Init();
}
diff --git a/chromium/ui/views/controls/menu/menu_config.h b/chromium/ui/views/controls/menu/menu_config.h
index 885aa4ceb9e..893c242018d 100644
--- a/chromium/ui/views/controls/menu/menu_config.h
+++ b/chromium/ui/views/controls/menu/menu_config.h
@@ -200,6 +200,9 @@ struct VIEWS_EXPORT MenuConfig {
// Whether all types of menus use prefix selection for items.
bool all_menus_use_prefix_selection;
+ // Margins for footnotes (HIGHLIGHTED item at the end of a menu).
+ int footnote_vertical_margin;
+
private:
// Configures a MenuConfig as appropriate for the current platform.
void Init();
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index 237a19181f2..f30abb99f6f 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -415,7 +415,8 @@ void MenuController::Run(Widget* parent,
const gfx::Rect& bounds,
MenuAnchorPosition position,
bool context_menu,
- bool is_nested_drag) {
+ bool is_nested_drag,
+ base::flat_set<int> alerted_commands) {
exit_type_ = EXIT_NONE;
possible_drag_ = false;
drag_in_progress_ = false;
@@ -454,6 +455,7 @@ void MenuController::Run(Widget* parent,
DCHECK_EQ(owner_, parent);
} else {
showing_ = true;
+ alerted_commands_ = alerted_commands;
if (owner_)
owner_->RemoveObserver(this);
@@ -781,7 +783,7 @@ void MenuController::OnMouseMoved(SubmenuView* source,
ConvertLocatedEventForRootView(source, root_view, &event_for_root);
View* view = root_view->GetEventHandlerForPoint(event_for_root.location());
Button* button = Button::AsButton(view);
- if (button && button->IsHotTracked())
+ if (button)
SetHotTrackedButton(button);
}
@@ -921,7 +923,7 @@ void MenuController::ViewHierarchyChanged(
bool MenuController::GetDropFormats(
SubmenuView* source,
int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) {
+ std::set<ui::ClipboardFormatType>* format_types) {
return source->GetMenuItem()->GetDelegate()->GetDropFormats(
source->GetMenuItem(), formats, format_types);
}
@@ -1247,9 +1249,6 @@ void MenuController::SetSelection(MenuItemView* menu_item,
(selection_types & SELECTION_OPEN_SUBMENU) != 0);
}
- if (menu_item && menu_item->GetDelegate())
- menu_item->GetDelegate()->SelectionChanged(menu_item);
-
DCHECK(menu_item || (selection_types & SELECTION_EXIT) != 0);
pending_state_.item = menu_item;
@@ -1948,7 +1947,15 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) {
// than 0) is fine.
const int kGroupingId = 1001;
+ // Show alerts on the requested MenuItemViews.
+ for (int i = 0; i < item->GetSubmenu()->GetMenuItemCount(); ++i) {
+ MenuItemView* subitem = item->GetSubmenu()->GetMenuItemAt(i);
+ if (alerted_commands_.contains(subitem->GetCommand()))
+ subitem->SetAlerted(true);
+ }
+
item->GetSubmenu()->ShowAt(owner_, bounds, do_capture);
+
// Figure out if the mouse is under the menu; if so, remember the mouse
// location so we can ignore the first mouse move event(s) with that
// location. We do this after ShowAt because ConvertPointFromScreen
diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h
index 94538e47b29..5407ce2d1a5 100644
--- a/chromium/ui/views/controls/menu/menu_controller.h
+++ b/chromium/ui/views/controls/menu/menu_controller.h
@@ -85,16 +85,16 @@ class VIEWS_EXPORT MenuController
// If a menu is currently active, this returns the controller for it.
static MenuController* GetActiveInstance();
- // Runs the menu at the specified location. If the menu was configured to
- // block, the selected item is returned. If the menu does not block this
- // returns NULL immediately.
+ // Runs the menu at the specified location. Menu items with commands in
+ // |alerted_commands| will be rendered differently to draw attention to them.
void Run(Widget* parent,
MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
MenuAnchorPosition position,
bool context_menu,
- bool is_nested_drag);
+ bool is_nested_drag,
+ base::flat_set<int> alerted_commands = base::flat_set<int>());
bool for_drop() const { return for_drop_; }
@@ -164,7 +164,7 @@ class VIEWS_EXPORT MenuController
bool GetDropFormats(SubmenuView* source,
int* formats,
- std::set<ui::Clipboard::FormatType>* format_types);
+ std::set<ui::ClipboardFormatType>* format_types);
bool AreDropTypesRequired(SubmenuView* source);
bool CanDrop(SubmenuView* source, const ui::OSExchangeData& data);
void OnDragEntered(SubmenuView* source, const ui::DropTargetEvent& event);
@@ -741,6 +741,9 @@ class VIEWS_EXPORT MenuController
std::unique_ptr<MenuPreTargetHandler> menu_pre_target_handler_;
+ // Set of menu commands that should be displayed with an alert.
+ base::flat_set<int> alerted_commands_;
+
DISALLOW_COPY_AND_ASSIGN(MenuController);
};
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
index 8cce8de8e18..e0a3886e0fe 100644
--- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -965,6 +965,8 @@ TEST_F(MenuControllerTest, SelectChildButtonView) {
ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location,
ui::EventTimeForNow(), 0, 0);
ProcessMouseMoved(sub_menu, event);
+ EXPECT_EQ(button1, GetHotButton());
+ EXPECT_TRUE(button1->IsHotTracked());
// Incrementing selection should move hot tracking to the second button (next
// after the first button).
@@ -1712,11 +1714,6 @@ TEST_F(MenuControllerTest, GrowingMenuMovesLaterallyNotVertically) {
// This tests that mouse moved events from the initial position of the mouse
// when the menu was shown don't select the menu item at the mouse position.
TEST_F(MenuControllerTest, MouseAtMenuItemOnShow) {
- // aura::Window::MoveCursorTo check fails in Mus due to null
- // window_manager_client_.
- if (IsMus())
- return;
-
// Most tests create an already shown menu but this test needs one that's
// not shown, so it can show it. The mouse position is remembered when
// the menu is shown.
diff --git a/chromium/ui/views/controls/menu/menu_delegate.cc b/chromium/ui/views/controls/menu/menu_delegate.cc
index f8a91bcd5c7..d6157d86a7b 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.cc
+++ b/chromium/ui/views/controls/menu/menu_delegate.cc
@@ -81,7 +81,7 @@ bool MenuDelegate::CanDrop(MenuItemView* menu, const OSExchangeData& data) {
bool MenuDelegate::GetDropFormats(
MenuItemView* menu,
int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) {
+ std::set<ui::ClipboardFormatType>* format_types) {
return false;
}
diff --git a/chromium/ui/views/controls/menu/menu_delegate.h b/chromium/ui/views/controls/menu/menu_delegate.h
index 69a8ed510b6..921aef245bf 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.h
+++ b/chromium/ui/views/controls/menu/menu_delegate.h
@@ -150,10 +150,9 @@ class VIEWS_EXPORT MenuDelegate {
virtual bool CanDrop(MenuItemView* menu, const OSExchangeData& data);
// See view for a description of this method.
- virtual bool GetDropFormats(
- MenuItemView* menu,
- int* formats,
- std::set<ui::Clipboard::FormatType>* format_types);
+ virtual bool GetDropFormats(MenuItemView* menu,
+ int* formats,
+ std::set<ui::ClipboardFormatType>* format_types);
// See view for a description of this method.
virtual bool AreDropTypesRequired(MenuItemView* menu);
@@ -194,10 +193,6 @@ class VIEWS_EXPORT MenuDelegate {
// Views that are not MenuItemViews.
virtual bool ShouldCloseOnDragComplete();
- // Notification that the user has highlighted the specified item.
- virtual void SelectionChanged(MenuItemView* menu) {
- }
-
// Notification the menu has closed. This will not be called if MenuRunner is
// deleted during calls to ExecuteCommand().
virtual void OnMenuClosed(MenuItemView* menu) {}
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index 91889d70bf7..91b584b0f6d 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -10,7 +10,6 @@
#include "build/build_config.h"
#include "ui/aura/window_observer.h"
#include "ui/events/gestures/gesture_recognizer.h"
-#include "ui/gfx/path.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/controls/menu/menu_host_root_view.h"
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index c26f578b8c6..72346e78c5b 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -31,6 +31,7 @@
#include "ui/views/controls/menu/menu_separator.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/controls/separator.h"
+#include "ui/views/view_properties.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -285,6 +286,11 @@ MenuItemView* MenuItemView::AddMenuItemAt(
item->SetIcon(icon);
if (type == SUBMENU || type == ACTIONABLE_SUBMENU)
item->CreateSubmenu();
+ if (type == HIGHLIGHTED) {
+ const MenuConfig& config = MenuConfig::instance();
+ item->SetMargins(config.footnote_vertical_margin,
+ config.footnote_vertical_margin);
+ }
if (GetDelegate() && !GetDelegate()->IsCommandVisible(item_id))
item->SetVisible(false);
submenu_->AddChildViewAt(item, index);
@@ -490,6 +496,7 @@ int MenuItemView::GetHeightForWidth(int width) const {
int height = child_at(0)->GetHeightForWidth(width);
if (!icon_view_ && GetRootMenuItem()->has_icons())
height = std::max(height, MenuConfig::instance().check_height);
+
height += GetBottomMargin() + GetTopMargin();
return height;
@@ -611,9 +618,22 @@ void MenuItemView::Layout() {
return;
if (IsContainer()) {
- View* child = child_at(0);
- gfx::Size size = child->GetPreferredSize();
- child->SetBounds(0, GetTopMargin(), size.width(), size.height());
+ View* const child = child_at(0);
+ const gfx::Size child_size = child->GetPreferredSize();
+
+ // Get child's margins or use default empty margins.
+ const gfx::Insets* margins_prop = child->GetProperty(views::kMarginsKey);
+ const gfx::Insets child_margins =
+ margins_prop ? *margins_prop
+ : gfx::Insets(GetTopMargin(), 0, GetBottomMargin(), 0);
+
+ gfx::Rect max_bounds = GetContentsBounds();
+ max_bounds.Inset(child_margins);
+
+ gfx::Rect bounds = gfx::Rect(child_margins.left(), child_margins.top(),
+ child_size.width(), child_size.height());
+ bounds.Intersect(max_bounds);
+ child->SetBoundsRect(bounds);
} else {
// Child views are laid out right aligned and given the full height. To
// right align start with the last view and progress to the first.
@@ -699,6 +719,11 @@ void MenuItemView::SetCornerRadius(int radius) {
invalidate_dimensions(); // Triggers preferred size recalculation.
}
+void MenuItemView::SetAlerted(bool alerted) {
+ alerted_ = alerted;
+ SchedulePaint();
+}
+
MenuItemView::MenuItemView(MenuItemView* parent,
int command,
MenuItemView::Type type)
@@ -991,18 +1016,26 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
void MenuItemView::PaintBackground(gfx::Canvas* canvas,
PaintButtonMode mode,
bool render_selection) {
- if (GetType() == HIGHLIGHTED) {
+ if (GetType() == HIGHLIGHTED || alerted_) {
// 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;
+ ui::NativeTheme::ColorId color_id;
+ if (GetType() == HIGHLIGHTED) {
+ color_id =
+ render_selection
+ ? ui::NativeTheme::
+ kColorId_FocusedHighlightedMenuItemBackgroundColor
+ : ui::NativeTheme::kColorId_HighlightedMenuItemBackgroundColor;
+ } else {
+ color_id = ui::NativeTheme::kColorId_MenuItemAlertBackgroundColor;
+ }
+
+ const SkColor color = GetNativeTheme()->GetSystemColor(color_id);
+
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setStyle(cc::PaintFlags::kFill_Style);
- flags.setColor(GetNativeTheme()->GetSystemColor(color_id));
+ flags.setColor(color);
// 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
@@ -1115,7 +1148,14 @@ int MenuItemView::GetTopMargin() const {
? MenuConfig::instance().item_top_margin
: MenuConfig::instance().item_no_icon_top_margin;
}
- return margin + corner_radius_ / 2;
+
+ if (IsContainer()) {
+ const gfx::Insets* child_margins = child_at(0)->GetProperty(kMarginsKey);
+ if (child_margins)
+ margin += child_margins->top();
+ }
+
+ return margin;
}
int MenuItemView::GetBottomMargin() const {
@@ -1126,18 +1166,32 @@ int MenuItemView::GetBottomMargin() const {
? 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);
+
+ if (IsContainer()) {
+ const gfx::Insets* child_margins = child_at(0)->GetProperty(kMarginsKey);
+ if (child_margins)
+ margin += child_margins->bottom();
+ }
+
+ return margin;
}
gfx::Size MenuItemView::GetChildPreferredSize() const {
if (!has_children())
return gfx::Size();
- if (IsContainer())
- return child_at(0)->GetPreferredSize();
+ if (IsContainer()) {
+ // Take into account both the child's preferred size and their left and
+ // right margins. The top and bottom margins are already accounted for in
+ // GetTopMargin() and GetBottomMargin().
+ const gfx::Insets* child_margins_prop =
+ child_at(0)->GetProperty(kMarginsKey);
+ const gfx::Insets child_margins =
+ child_margins_prop ? *child_margins_prop : gfx::Insets();
+ gfx::Size child_size = child_at(0)->GetPreferredSize();
+ child_size.Enlarge(child_margins.width(), 0);
+ return child_size;
+ }
int width = 0;
for (int i = 0; i < child_count(); ++i) {
@@ -1251,6 +1305,12 @@ void MenuItemView::ApplyMinimumDimensions(MenuItemDimensions* dims) const {
if (!GetMenuController() || GetMenuController()->is_combobox())
return;
+ // TODO(nicolaso): PaintBackground() doesn't cover the whole area in footnotes
+ // when minimum height is set too high. For now, just ignore minimum height
+ // for HIGHLIGHTED elements.
+ if (GetType() == HIGHLIGHTED)
+ return;
+
int used =
dims->standard_width + dims->children_width + dims->minor_text_width;
const MenuConfig& config = MenuConfig::instance();
diff --git a/chromium/ui/views/controls/menu/menu_item_view.h b/chromium/ui/views/controls/menu/menu_item_view.h
index f0e80ee12e6..98214a30d20 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.h
+++ b/chromium/ui/views/controls/menu/menu_item_view.h
@@ -367,6 +367,11 @@ class VIEWS_EXPORT MenuItemView : public View {
// border radius, if they are both the same value.
void SetCornerRadius(int radius);
+ // Show an alert on this menu item. An alerted menu item is rendered
+ // differently to draw attention to it.
+ void SetAlerted(bool alerted);
+ bool Alerted() const { return alerted_; }
+
protected:
// Creates a MenuItemView. This is used by the various AddXXX methods.
MenuItemView(MenuItemView* parent, int command, Type type);
@@ -613,6 +618,9 @@ class VIEWS_EXPORT MenuItemView : public View {
// an ACTIONABLE_SUBMENU.
Separator* vertical_separator_;
+ // Whether this menu item is rendered differently to draw attention to it.
+ bool alerted_ = false;
+
DISALLOW_COPY_AND_ASSIGN(MenuItemView);
};
diff --git a/chromium/ui/views/controls/menu/menu_item_view_unittest.cc b/chromium/ui/views/controls/menu/menu_item_view_unittest.cc
index e4f42f008b4..c3e9afd0ebe 100644
--- a/chromium/ui/views/controls/menu/menu_item_view_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view_unittest.cc
@@ -4,16 +4,21 @@
#include "ui/views/controls/menu/menu_item_view.h"
+#include <memory>
+#include <utility>
+
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/canvas_painter.h"
+#include "ui/gfx/geometry/insets.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/test/menu_test_utils.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/vector_icons.h"
+#include "ui/views/view_properties.h"
namespace views {
@@ -171,6 +176,41 @@ TEST(MenuItemViewUnitTest, UseMnemonicOnPlatform) {
}
}
+// Tests MenuItemView::Layout() in the IsContainer() case.
+TEST(MenuItemViewUnitTest, ContainerLayout) {
+ TestMenuItemView root_menu;
+ MenuItemView* item = root_menu.AppendMenuItemWithLabel(1, base::string16());
+
+ // We make our menu item a simple container for our view.
+ View* child_view = item->AddChildView(std::make_unique<View>());
+
+ // We want to check that MenuItemView::Layout() respects the child's preferred
+ // size and margins.
+ const gfx::Size child_size(200, 50);
+ const gfx::Insets child_margins(5, 10);
+ child_view->SetPreferredSize(child_size);
+ child_view->SetProperty(kMarginsKey, new gfx::Insets(child_margins));
+
+ // SubmenuView does not lay out its children unless it is contained in a
+ // view. Make a simple container for it. We have to call set_owned_by_client()
+ // since |submenu| is owned by |root_menu|.
+ SubmenuView* submenu = root_menu.GetSubmenu();
+ submenu->set_owned_by_client();
+ auto submenu_parent = std::make_unique<View>();
+ submenu_parent->AddChildView(submenu);
+ submenu_parent->SetPosition(gfx::Point(0, 0));
+ submenu_parent->SetSize(submenu->GetPreferredSize());
+
+ // Get |child_view|'s bounds in |item|'s coordinate space, and check that they
+ // align with |child_view|'s margins and preferred size.
+ const gfx::Rect child_bounds =
+ child_view->ConvertRectToParent(child_view->GetLocalBounds());
+ EXPECT_EQ(child_bounds.x(), child_margins.left());
+ EXPECT_EQ(child_bounds.y(), child_margins.top());
+ EXPECT_EQ(child_bounds.width(), child_size.width());
+ EXPECT_EQ(child_bounds.height(), child_size.height());
+}
+
class MenuItemViewPaintUnitTest : public ViewsTestBase {
public:
MenuItemViewPaintUnitTest() {}
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index 08132c522c1..c91415cb1e9 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -220,22 +220,6 @@ bool MenuModelAdapter::IsItemChecked(int id) const {
return false;
}
-void MenuModelAdapter::SelectionChanged(MenuItemView* menu) {
- // Ignore selection of the root menu.
- if (menu == menu->GetRootMenuItem())
- return;
-
- const int id = menu->GetCommand();
- ui::MenuModel* model = menu_model_;
- int index = 0;
- if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
- model->HighlightChangedTo(index);
- return;
- }
-
- NOTREACHED();
-}
-
void MenuModelAdapter::WillShowMenu(MenuItemView* menu) {
// Look up the menu model for this menu.
const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.h b/chromium/ui/views/controls/menu/menu_model_adapter.h
index e52edfe5edd..a3598719063 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.h
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.h
@@ -75,7 +75,6 @@ class VIEWS_EXPORT MenuModelAdapter : public MenuDelegate {
bool IsCommandEnabled(int id) const override;
bool IsCommandVisible(int id) const override;
bool IsItemChecked(int id) const override;
- void SelectionChanged(MenuItemView* menu) override;
void WillShowMenu(MenuItemView* menu) override;
void WillHideMenu(MenuItemView* menu) override;
void OnMenuClosed(MenuItemView* menu) override;
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
index 392f6c3ed34..2d95b3cdeac 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -82,8 +82,6 @@ class MenuModelBase : public ui::MenuModel {
return items_[index].submenu;
}
- void HighlightChangedTo(int index) override {}
-
void ActivatedAt(int index) override { set_last_activation(index); }
void ActivatedAt(int index, int event_flags) override { ActivatedAt(index); }
@@ -341,11 +339,6 @@ TEST_F(MenuModelAdapterTest, BasicTest) {
const int actionable_submenu_index = 5;
CheckSubmenu(model, menu, &delegate, kRootIdBase + actionable_submenu_index,
2, actionable_submenu_index, kActionableSubmenuIdBase);
-
- // Check that selecting the root item is safe. The MenuModel does
- // not care about the root so MenuModelAdapter should do nothing
- // (not hit the NOTREACHED check) when the root is selected.
- static_cast<views::MenuDelegate*>(&delegate)->SelectionChanged(menu);
}
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_runner.cc b/chromium/ui/views/controls/menu/menu_runner.cc
index bd16bfc34fe..1c4ffea5cf6 100644
--- a/chromium/ui/views/controls/menu/menu_runner.cc
+++ b/chromium/ui/views/controls/menu/menu_runner.cc
@@ -32,7 +32,8 @@ void MenuRunner::RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
MenuAnchorPosition anchor,
- ui::MenuSourceType source_type) {
+ ui::MenuSourceType source_type,
+ base::flat_set<int> alerted_commands) {
// If we are shown on mouse press, we will eat the subsequent mouse down and
// the parent widget will not be able to reset its state (it might have mouse
// capture from the mouse down). So we clear its state here.
@@ -69,7 +70,8 @@ void MenuRunner::RunMenuAt(Widget* parent,
}
}
- impl_->RunMenuAt(parent, button, bounds, anchor, run_types_);
+ impl_->RunMenuAt(parent, button, bounds, anchor, run_types_,
+ alerted_commands);
}
bool MenuRunner::IsRunning() const {
diff --git a/chromium/ui/views/controls/menu/menu_runner.h b/chromium/ui/views/controls/menu/menu_runner.h
index 88b4bb43448..dfa8bcfa18f 100644
--- a/chromium/ui/views/controls/menu/menu_runner.h
+++ b/chromium/ui/views/controls/menu/menu_runner.h
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/controls/menu/menu_types.h"
@@ -115,12 +116,15 @@ class VIEWS_EXPORT MenuRunner {
// Runs the menu. MenuDelegate::OnMenuClosed will be notified of the results.
// If |anchor| uses a |BUBBLE_..| type, the bounds will get determined by
- // using |bounds| as the thing to point at in screen coordinates.
+ // using |bounds| as the thing to point at in screen coordinates. Menu items
+ // with commands in |alerted_commands| will be rendered differently to draw
+ // attention to them.
void RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
MenuAnchorPosition anchor,
- ui::MenuSourceType source_type);
+ ui::MenuSourceType source_type,
+ base::flat_set<int> alerted_commands = base::flat_set<int>());
// Returns true if we're in a nested run loop running the menu.
bool IsRunning() const;
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl.cc b/chromium/ui/views/controls/menu/menu_runner_impl.cc
index 3f1fb8af38b..6ff3a6a37e9 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl.cc
+++ b/chromium/ui/views/controls/menu/menu_runner_impl.cc
@@ -81,7 +81,8 @@ void MenuRunnerImpl::RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
MenuAnchorPosition anchor,
- int32_t run_types) {
+ int32_t run_types,
+ base::flat_set<int> alerted_commands) {
closing_event_time_ = base::TimeTicks();
if (running_) {
// Ignore requests to show the menu while it's already showing. MenuItemView
@@ -137,7 +138,7 @@ void MenuRunnerImpl::RunMenuAt(Widget* parent,
controller->Run(parent, button, menu_, bounds, anchor,
(run_types & MenuRunner::CONTEXT_MENU) != 0,
- (run_types & MenuRunner::NESTED_DRAG) != 0);
+ (run_types & MenuRunner::NESTED_DRAG) != 0, alerted_commands);
}
void MenuRunnerImpl::Cancel() {
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl.h b/chromium/ui/views/controls/menu/menu_runner_impl.h
index 22e490a1af5..9367a2abbe1 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl.h
+++ b/chromium/ui/views/controls/menu/menu_runner_impl.h
@@ -10,6 +10,7 @@
#include <set>
#include "base/compiler_specific.h"
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
@@ -39,11 +40,13 @@ class VIEWS_EXPORT MenuRunnerImpl : public MenuRunnerImplInterface,
bool IsRunning() const override;
void Release() override;
- void RunMenuAt(Widget* parent,
- MenuButton* button,
- const gfx::Rect& bounds,
- MenuAnchorPosition anchor,
- int32_t run_types) override;
+ void RunMenuAt(
+ Widget* parent,
+ MenuButton* button,
+ const gfx::Rect& bounds,
+ MenuAnchorPosition anchor,
+ int32_t run_types,
+ base::flat_set<int> alerted_commands = base::flat_set<int>()) override;
void Cancel() override;
base::TimeTicks GetClosingEventTime() const override;
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl_adapter.cc b/chromium/ui/views/controls/menu/menu_runner_impl_adapter.cc
index 08b8b81741c..84121b264a0 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_runner_impl_adapter.cc
@@ -30,8 +30,9 @@ void MenuRunnerImplAdapter::RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
MenuAnchorPosition anchor,
- int32_t types) {
- impl_->RunMenuAt(parent, button, bounds, anchor, types);
+ int32_t types,
+ base::flat_set<int> alerted_commands) {
+ impl_->RunMenuAt(parent, button, bounds, anchor, types, alerted_commands);
}
void MenuRunnerImplAdapter::Cancel() {
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl_adapter.h b/chromium/ui/views/controls/menu/menu_runner_impl_adapter.h
index e70d7b60168..dd713eb92bb 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl_adapter.h
+++ b/chromium/ui/views/controls/menu/menu_runner_impl_adapter.h
@@ -32,7 +32,8 @@ class VIEWS_EXPORT MenuRunnerImplAdapter : public MenuRunnerImplInterface {
MenuButton* button,
const gfx::Rect& bounds,
MenuAnchorPosition anchor,
- int32_t types) override;
+ int32_t types,
+ base::flat_set<int> alerted_commands) override;
void Cancel() override;
base::TimeTicks GetClosingEventTime() const override;
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h
index 599000dd285..5b2382aa7dd 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h
+++ b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h
@@ -29,11 +29,13 @@ class VIEWS_EXPORT MenuRunnerImplCocoa : public MenuRunnerImplInterface {
bool IsRunning() const override;
void Release() override;
- void RunMenuAt(Widget* parent,
- MenuButton* button,
- const gfx::Rect& bounds,
- MenuAnchorPosition anchor,
- int32_t run_types) override;
+ void RunMenuAt(
+ Widget* parent,
+ MenuButton* button,
+ const gfx::Rect& bounds,
+ MenuAnchorPosition anchor,
+ int32_t run_types,
+ base::flat_set<int> alerted_commands = base::flat_set<int>()) override;
void Cancel() override;
base::TimeTicks GetClosingEventTime() const override;
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 f67cdcbd9f9..91585b2da12 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -167,7 +167,8 @@ void MenuRunnerImplCocoa::RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
MenuAnchorPosition anchor,
- int32_t run_types) {
+ int32_t run_types,
+ base::flat_set<int> alerted_commands) {
DCHECK(!IsRunning());
DCHECK(parent);
closing_event_time_ = base::TimeTicks();
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl_interface.h b/chromium/ui/views/controls/menu/menu_runner_impl_interface.h
index 6a9e1f44576..eaea27e4976 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl_interface.h
+++ b/chromium/ui/views/controls/menu/menu_runner_impl_interface.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "base/callback_forward.h"
+#include "base/containers/flat_set.h"
#include "ui/views/controls/menu/menu_runner.h"
namespace views {
@@ -34,11 +35,13 @@ class MenuRunnerImplInterface {
virtual void Release() = 0;
// Runs the menu. See MenuRunner::RunMenuAt for more details.
- virtual void RunMenuAt(Widget* parent,
- MenuButton* button,
- const gfx::Rect& bounds,
- MenuAnchorPosition anchor,
- int32_t run_types) = 0;
+ virtual void RunMenuAt(
+ Widget* parent,
+ MenuButton* button,
+ const gfx::Rect& bounds,
+ MenuAnchorPosition anchor,
+ int32_t run_types,
+ base::flat_set<int> alerted_commands = base::flat_set<int>()) = 0;
// Hides and cancels the menu.
virtual void Cancel() = 0;
diff --git a/chromium/ui/views/controls/menu/menu_runner_unittest.cc b/chromium/ui/views/controls/menu/menu_runner_unittest.cc
index 577c4cceb03..e300385ee67 100644
--- a/chromium/ui/views/controls/menu/menu_runner_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_runner_unittest.cc
@@ -148,11 +148,6 @@ TEST_F(MenuRunnerTest, AsynchronousRun) {
// Tests that when a menu is run asynchronously, key events are handled properly
// by testing that Escape key closes the menu.
TEST_F(MenuRunnerTest, AsynchronousKeyEventHandling) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
InitMenuRunner(0);
MenuRunner* runner = menu_runner();
runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
@@ -170,11 +165,6 @@ TEST_F(MenuRunnerTest, AsynchronousKeyEventHandling) {
// Tests that a key press on a US keyboard layout activates the correct menu
// item.
TEST_F(MenuRunnerTest, LatinMnemonic) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
// Menus that use prefix selection don't support mnemonics - the input is
// always part of the prefix.
if (MenuConfig::instance().all_menus_use_prefix_selection)
@@ -201,11 +191,6 @@ TEST_F(MenuRunnerTest, LatinMnemonic) {
// Tests that a key press on a non-US keyboard layout activates the correct menu
// item. Disabled on Windows because a WM_CHAR event does not activate an item.
TEST_F(MenuRunnerTest, NonLatinMnemonic) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
// Menus that use prefix selection don't support mnemonics - the input is
// always part of the prefix.
if (MenuConfig::instance().all_menus_use_prefix_selection)
@@ -332,6 +317,21 @@ TEST_F(MenuRunnerTest, NestingDuringDrag) {
EXPECT_NE(nullptr, delegate->on_menu_closed_menu());
}
+TEST_F(MenuRunnerTest, AlertsShown) {
+ InitMenuRunner(0);
+ MenuRunner* runner = menu_runner();
+
+ base::flat_set<int> alerted_commands{2};
+ runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+ ui::MENU_SOURCE_NONE, alerted_commands);
+ EXPECT_TRUE(runner->IsRunning());
+
+ MenuItemView* normal_item = menu_item_view()->GetMenuItemByID(1);
+ MenuItemView* alerted_item = menu_item_view()->GetMenuItemByID(2);
+ EXPECT_FALSE(normal_item->Alerted());
+ EXPECT_TRUE(alerted_item->Alerted());
+}
+
namespace {
// An EventHandler that launches a menu in response to a mouse press.
@@ -370,8 +370,7 @@ class MenuRunnerWidgetTest : public MenuRunnerTest {
std::unique_ptr<ui::test::EventGenerator> EventGeneratorForWidget(
Widget* widget) {
return std::make_unique<ui::test::EventGenerator>(
- IsMus() ? GetRootWindow(widget) : GetContext(),
- widget->GetNativeWindow());
+ GetContext(), widget->GetNativeWindow());
}
void AddMenuLauncherEventHandler(Widget* widget) {
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 0ad986a75c3..43752f51ba8 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -187,7 +187,7 @@ MenuScrollViewContainer::MenuScrollViewContainer(SubmenuView* content_view)
CreateBorder();
}
-bool MenuScrollViewContainer::HasBubbleBorder() {
+bool MenuScrollViewContainer::HasBubbleBorder() const {
return arrow_ != BubbleBorder::NONE;
}
@@ -207,8 +207,10 @@ 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());
+ const MenuConfig& config = MenuConfig::instance();
+ // Leave space for the menu border, below the footnote.
+ if (GetFootnote() && config.use_outer_border && !HasBubbleBorder())
+ prefsize.Enlarge(0, 1);
return prefsize;
}
@@ -220,16 +222,18 @@ void MenuScrollViewContainer::Layout() {
int content_height = height() - insets.height();
MenuItemView* footnote = GetFootnote();
if (!scroll_up_button_->visible()) {
- if (footnote && bubble_border_)
- footnote->SetCornerRadius(bubble_border_->GetBorderCornerRadius());
+ if (footnote)
+ footnote->SetCornerRadius(corner_radius_);
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)
+ if (footnote) {
footnote->SetCornerRadius(0);
+ content_height -= corner_radius_;
+ }
gfx::Size pref = scroll_up_button_->GetPreferredSize();
scroll_up_button_->SetBounds(x, y, width, pref.height());
@@ -299,13 +303,14 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
bool use_outer_border =
menu_config.use_outer_border ||
(native_theme && native_theme->UsesHighContrastColors());
- int corner_radius = menu_config.CornerRadiusForMenu(controller);
- int padding = use_outer_border && corner_radius > 0
+ corner_radius_ = menu_config.CornerRadiusForMenu(controller);
+ int padding = use_outer_border && corner_radius_ > 0
? kBorderPaddingDueToRoundedCorners
: 0;
const int vertical_inset =
- (corner_radius ? corner_radius : menu_config.menu_vertical_border_size) +
+ (corner_radius_ ? corner_radius_
+ : menu_config.menu_vertical_border_size) +
padding;
const int horizontal_inset =
menu_config.menu_horizontal_border_size + padding;
@@ -318,7 +323,7 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
ui::NativeTheme::kColorId_MenuBorderColor)
: gfx::kPlaceholderColor;
SetBorder(views::CreateBorderPainter(
- std::make_unique<views::RoundRectPainter>(color, corner_radius),
+ std::make_unique<views::RoundRectPainter>(color, corner_radius_),
gfx::Insets(vertical_inset, horizontal_inset, bottom_inset,
horizontal_inset)));
} else {
@@ -343,6 +348,8 @@ void MenuScrollViewContainer::CreateBubbleBorder() {
scroll_view_->GetContents()->SetBorder(CreateEmptyBorder(insets));
}
+ corner_radius_ = bubble_border_->GetBorderCornerRadius();
+
SetBorder(std::unique_ptr<Border>(bubble_border_));
SetBackground(std::make_unique<BubbleBackground>(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 290fe81bb33..7c8548bdbc4 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
@@ -26,8 +26,8 @@ class MenuScrollViewContainer : public View {
View* scroll_down_button() const { return scroll_down_button_; }
View* scroll_up_button() const { return scroll_up_button_; }
- // External function to check if the bubble border is usd.
- bool HasBubbleBorder();
+ // External function to check if the bubble border is used.
+ bool HasBubbleBorder() const;
// Offsets the Arrow from the default location.
void SetBubbleArrowOffset(int offset);
@@ -78,6 +78,9 @@ class MenuScrollViewContainer : public View {
// Weak reference to the currently set border.
BubbleBorder* bubble_border_ = nullptr;
+ // Corner radius of the background.
+ int corner_radius_ = 0;
+
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 04c38f5c364..0796aec6762 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -241,7 +241,7 @@ void SubmenuView::PaintChildren(const PaintInfo& paint_info) {
bool SubmenuView::GetDropFormats(
int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) {
+ std::set<ui::ClipboardFormatType>* format_types) {
DCHECK(GetMenuItem()->GetMenuController());
return GetMenuItem()->GetMenuController()->GetDropFormats(this, formats,
format_types);
@@ -428,8 +428,11 @@ void SubmenuView::Close() {
}
void SubmenuView::Hide() {
- if (host_)
+ if (host_) {
host_->HideMenuHost();
+ NotifyAccessibilityEvent(ax::mojom::Event::kMenuPopupHide, true);
+ }
+
if (scroll_animator_->is_scrolling())
scroll_animator_->Stop();
}
diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h
index 37056577fe9..23c26fcb9bc 100644
--- a/chromium/ui/views/controls/menu/submenu_view.h
+++ b/chromium/ui/views/controls/menu/submenu_view.h
@@ -78,9 +78,8 @@ class VIEWS_EXPORT SubmenuView : public View,
void PaintChildren(const PaintInfo& paint_info) override;
// Drag and drop methods. These are forwarded to the MenuController.
- bool GetDropFormats(
- int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) override;
+ bool GetDropFormats(int* formats,
+ std::set<ui::ClipboardFormatType>* format_types) override;
bool AreDropTypesRequired() override;
bool CanDrop(const OSExchangeData& data) override;
void OnDragEntered(const ui::DropTargetEvent& event) override;
diff --git a/chromium/ui/views/controls/native/native_view_host.cc b/chromium/ui/views/controls/native/native_view_host.cc
index 270f22b0ece..86c7b558b8b 100644
--- a/chromium/ui/views/controls/native/native_view_host.cc
+++ b/chromium/ui/views/controls/native/native_view_host.cc
@@ -49,6 +49,10 @@ void NativeViewHost::Detach() {
Detach(false);
}
+void NativeViewHost::SetParentAccessible(gfx::NativeViewAccessible accessible) {
+ native_wrapper_->SetParentAccessible(accessible);
+}
+
bool NativeViewHost::SetCornerRadius(int corner_radius) {
return SetCustomMask(views::Painter::CreatePaintedLayer(
views::Painter::CreateSolidRoundRectPainter(SK_ColorBLACK,
@@ -60,6 +64,10 @@ bool NativeViewHost::SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) {
return native_wrapper_->SetCustomMask(std::move(mask));
}
+void NativeViewHost::SetHitTestTopInset(int top_inset) {
+ native_wrapper_->SetHitTestTopInset(top_inset);
+}
+
void NativeViewHost::SetNativeViewSize(const gfx::Size& size) {
if (native_view_size_ == size)
return;
diff --git a/chromium/ui/views/controls/native/native_view_host.h b/chromium/ui/views/controls/native/native_view_host.h
index 5c47f29d258..5923cc46273 100644
--- a/chromium/ui/views/controls/native/native_view_host.h
+++ b/chromium/ui/views/controls/native/native_view_host.h
@@ -57,6 +57,11 @@ class VIEWS_EXPORT NativeViewHost : public View {
// NB: This does not interact nicely with fast_resize.
bool SetCustomMask(std::unique_ptr<ui::LayerOwner> mask);
+ // Sets the height of the top region where the gfx::NativeView shouldn't be
+ // targeted. This will be used when another view is covering there
+ // temporarily, like the immersive fullscreen mode of ChromeOS.
+ void SetHitTestTopInset(int top_inset);
+
// Sets the size for the NativeView that may or may not match the size of this
// View when it is being captured. If the size does not match, scaling will
// occur. Pass an empty size to revert to the default behavior, where the
@@ -67,6 +72,10 @@ class VIEWS_EXPORT NativeViewHost : public View {
// if there's no attached native view or it has no container.
gfx::NativeView GetNativeViewContainer() const;
+ // Pass the parent accessible object to this host's native view so that
+ // it can return this value when querying its parent accessible.
+ void SetParentAccessible(gfx::NativeViewAccessible);
+
// Fast resizing will move the native view and clip its visible region, this
// will result in white areas and will not resize the content (so scrollbars
// will be all wrong and content will flow offscreen). Only use this
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.cc b/chromium/ui/views/controls/native/native_view_host_aura.cc
index dabae673dd7..6a3ab5076aa 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura.cc
@@ -12,9 +12,11 @@
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_occlusion_tracker.h"
+#include "ui/aura/window_targeter.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/paint_recorder.h"
+#include "ui/gfx/geometry/insets.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/painter.h"
#include "ui/views/view_constants_aura.h"
@@ -64,7 +66,7 @@ class NativeViewHostAura::ClippingWindowDelegate : public aura::WindowDelegate {
void OnWindowDestroyed(aura::Window* window) override {}
void OnWindowTargetVisibilityChanged(bool visible) override {}
bool HasHitTestMask() const override { return false; }
- void GetHitTestMask(gfx::Path* mask) const override {}
+ void GetHitTestMask(SkPath* mask) const override {}
private:
aura::Window* native_view_;
@@ -77,6 +79,8 @@ NativeViewHostAura::~NativeViewHostAura() {
host_->native_view()->RemoveObserver(this);
host_->native_view()->ClearProperty(views::kHostViewKey);
host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
+ host_->native_view()->ClearProperty(
+ aura::client::kParentNativeViewAccessibleKey);
clipping_window_->ClearProperty(views::kHostViewKey);
if (host_->native_view()->parent() == clipping_window_.get())
clipping_window_->RemoveChild(host_->native_view());
@@ -92,12 +96,19 @@ void NativeViewHostAura::AttachNativeView() {
host_->native_view()->AddObserver(this);
host_->native_view()->SetProperty(views::kHostViewKey,
static_cast<View*>(host_));
+
original_transform_ = host_->native_view()->transform();
original_transform_changed_ = false;
AddClippingWindow();
InstallMask();
}
+void NativeViewHostAura::SetParentAccessible(
+ gfx::NativeViewAccessible accessible) {
+ host_->native_view()->SetProperty(
+ aura::client::kParentNativeViewAccessibleKey, accessible);
+}
+
void NativeViewHostAura::NativeViewDetaching(bool destroyed) {
// This method causes a succession of window tree changes. ScopedPause ensures
// that occlusion is recomputed at the end of the method instead of after each
@@ -112,6 +123,8 @@ void NativeViewHostAura::NativeViewDetaching(bool destroyed) {
host_->native_view()->RemoveObserver(this);
host_->native_view()->ClearProperty(views::kHostViewKey);
host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
+ host_->native_view()->ClearProperty(
+ aura::client::kParentNativeViewAccessibleKey);
if (original_transform_changed_)
host_->native_view()->SetTransform(original_transform_);
host_->native_view()->Hide();
@@ -161,6 +174,13 @@ bool NativeViewHostAura::SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) {
#endif
}
+void NativeViewHostAura::SetHitTestTopInset(int top_inset) {
+ if (top_inset_ == top_inset)
+ return;
+ top_inset_ = top_inset;
+ UpdateInsets();
+}
+
void NativeViewHostAura::InstallClip(int x, int y, int w, int h) {
clip_rect_.reset(
new gfx::Rect(host_->ConvertRectToWidget(gfx::Rect(x, y, w, h))));
@@ -284,6 +304,7 @@ void NativeViewHostAura::CreateClippingWindow() {
clipping_window_->SetName("NativeViewHostAuraClip");
clipping_window_->layer()->SetMasksToBounds(true);
clipping_window_->SetProperty(views::kHostViewKey, static_cast<View*>(host_));
+ UpdateInsets();
}
void NativeViewHostAura::AddClippingWindow() {
@@ -340,4 +361,23 @@ void NativeViewHostAura::UninstallMask() {
mask_.reset();
}
+void NativeViewHostAura::UpdateInsets() {
+ if (!clipping_window_)
+ return;
+
+ if (top_inset_ == 0) {
+ // The window targeter needs to be uninstalled when not used; keeping empty
+ // targeter here actually conflicts with ash::ImmersiveWindowTargeter on
+ // immersive mode in Ash.
+ // TODO(mukai): fix this.
+ clipping_window_->SetEventTargeter(nullptr);
+ } else {
+ if (!clipping_window_->targeter()) {
+ clipping_window_->SetEventTargeter(
+ std::make_unique<aura::WindowTargeter>());
+ }
+ clipping_window_->targeter()->SetInsets(gfx::Insets(top_inset_, 0, 0, 0));
+ }
+}
+
} // namespace views
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 1e24714575b..ea29802c00a 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.h
+++ b/chromium/ui/views/controls/native/native_view_host_aura.h
@@ -34,6 +34,7 @@ class NativeViewHostAura : public NativeViewHostWrapper,
void AddedToWidget() override;
void RemovedFromWidget() override;
bool SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) override;
+ void SetHitTestTopInset(int top_inset) override;
void InstallClip(int x, int y, int w, int h) override;
bool HasInstalledClip() override;
void UninstallClip() override;
@@ -45,6 +46,7 @@ class NativeViewHostAura : public NativeViewHostWrapper,
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::NativeCursor GetCursor(int x, int y) override;
void SetVisible(bool visible) override;
+ void SetParentAccessible(gfx::NativeViewAccessible) override;
private:
friend class NativeViewHostAuraTest;
@@ -74,6 +76,9 @@ class NativeViewHostAura : public NativeViewHostWrapper,
// Unsets the mask layer on the native view's layer.
void UninstallMask();
+ // Updates the top insets of |clipping_window_|.
+ void UpdateInsets();
+
// Our associated NativeViewHost.
NativeViewHost* host_;
@@ -98,6 +103,9 @@ class NativeViewHostAura : public NativeViewHostWrapper,
// True if a transform different from the original was set.
bool original_transform_changed_ = false;
+ // The top insets to exclude the underlying native view from the target.
+ int top_inset_ = 0;
+
DISALLOW_COPY_AND_ASSIGN(NativeViewHostAura);
};
diff --git a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
index 4a7e05f70b8..c4d7e71b051 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
@@ -9,6 +9,9 @@
#include "base/macros.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_targeter.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/cursor/cursor.h"
#include "ui/events/event_utils.h"
#include "ui/views/controls/native/native_view_host.h"
@@ -335,18 +338,12 @@ TEST_F(NativeViewHostAuraTest, ParentAfterDetach) {
DestroyHost();
DestroyTopLevel();
- if (!IsMus()) {
- // The window is detached, so no longer associated with any Widget
- // hierarchy. The root window still owns it, but the test harness checks
- // for orphaned windows during TearDown().
- EXPECT_EQ(0u, test_observer.events().size())
- << (*test_observer.events().begin()).type;
- delete child_win;
- } else {
- // In mus and aura-mus, the child window is still attached to the
- // aura::WindowTreeHost for the Widget. So destroying the toplevel Widget
- // takes down the child window with it.
- }
+ // The window is detached, so no longer associated with any Widget
+ // hierarchy. The root window still owns it, but the test harness checks
+ // for orphaned windows during TearDown().
+ EXPECT_EQ(0u, test_observer.events().size())
+ << (*test_observer.events().begin()).type;
+ delete child_win;
ASSERT_EQ(1u, test_observer.events().size());
EXPECT_EQ(NativeViewHostWindowObserver::EVENT_DESTROYED,
@@ -518,4 +515,40 @@ TEST_F(NativeViewHostAuraTest, FocusManagerUpdatedDuringDestruction) {
EXPECT_EQ(nullptr, toplevel()->GetFocusManager()->GetFocusedView());
}
+namespace {
+
+ui::EventTarget* GetTarget(aura::Window* window, const gfx::Point& location) {
+ gfx::Point root_location = location;
+ aura::Window::ConvertPointToTarget(window, window->GetRootWindow(),
+ &root_location);
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, root_location, root_location,
+ base::TimeTicks::Now(), 0, 0);
+ return window->GetHost()->dispatcher()->event_targeter()->FindTargetForEvent(
+ window->GetRootWindow(), &event);
+}
+
+} // namespace
+
+TEST_F(NativeViewHostAuraTest, TopInsets) {
+ CreateHost();
+ toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
+ toplevel()->Show();
+
+ aura::Window* toplevel_window = toplevel()->GetNativeWindow();
+ aura::Window* child_window = child()->GetNativeWindow();
+ EXPECT_EQ(child_window, GetTarget(toplevel_window, gfx::Point(1, 1)));
+ EXPECT_EQ(child_window, GetTarget(toplevel_window, gfx::Point(1, 11)));
+
+ host()->SetHitTestTopInset(10);
+ EXPECT_EQ(toplevel_window, GetTarget(toplevel_window, gfx::Point(1, 1)));
+ EXPECT_EQ(child_window, GetTarget(toplevel_window, gfx::Point(1, 11)));
+
+ host()->SetHitTestTopInset(0);
+ EXPECT_EQ(child_window, GetTarget(toplevel_window, gfx::Point(1, 1)));
+ EXPECT_EQ(child_window, GetTarget(toplevel_window, gfx::Point(1, 11)));
+
+ DestroyHost();
+ DestroyTopLevel();
+}
+
} // namespace views
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 08a0ce36806..cfcd98fe91a 100644
--- a/chromium/ui/views/controls/native/native_view_host_mac.h
+++ b/chromium/ui/views/controls/native/native_view_host_mac.h
@@ -41,6 +41,7 @@ class NativeViewHostMac : public NativeViewHostWrapper,
void AddedToWidget() override;
void RemovedFromWidget() override;
bool SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) override;
+ void SetHitTestTopInset(int top_inset) override;
void InstallClip(int x, int y, int w, int h) override;
bool HasInstalledClip() override;
void UninstallClip() override;
@@ -52,6 +53,7 @@ class NativeViewHostMac : public NativeViewHostWrapper,
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::NativeCursor GetCursor(int x, int y) override;
void SetVisible(bool visible) override;
+ void SetParentAccessible(gfx::NativeViewAccessible) 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 7ce36315bfa..efd578dcff3 100644
--- a/chromium/ui/views/controls/native/native_view_host_mac.mm
+++ b/chromium/ui/views/controls/native/native_view_host_mac.mm
@@ -115,21 +115,23 @@ void NativeViewHostMac::AttachNativeView() {
DCHECK(host_->native_view());
DCHECK(!native_view_);
native_view_.reset([host_->native_view().GetNativeNSView() retain]);
+ if ([native_view_ conformsToProtocol:@protocol(ViewsHostable)]) {
+ id hostable = native_view_;
+ native_view_hostable_ = [hostable viewsHostableView];
+ }
EnsureNativeViewHasNoChildWidgets(native_view_);
auto* bridge_host = GetBridgedNativeWidgetHost();
DCHECK(bridge_host);
- 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)]) {
- id hostable = native_view_;
- native_view_hostable_ = [hostable viewsHostableView];
- if (native_view_hostable_)
- native_view_hostable_->OnViewsHostableAttached(this);
+ if (native_view_hostable_) {
+ native_view_hostable_->ViewsHostableAttach(this);
+ } else {
+ NSView* superview =
+ bridge_host->native_widget_mac()->GetNativeView().GetNativeNSView();
+ [superview addSubview:native_view_];
}
+ bridge_host->SetAssociationForView(host_, native_view_);
}
void NativeViewHostMac::NativeViewDetaching(bool destroyed) {
@@ -146,12 +148,12 @@ void NativeViewHostMac::NativeViewDetaching(bool destroyed) {
}
DCHECK(native_view_ == host_native_view);
- [native_view_ setHidden:YES];
- [native_view_ removeFromSuperview];
-
if (native_view_hostable_) {
- native_view_hostable_->OnViewsHostableDetached();
+ native_view_hostable_->ViewsHostableDetach();
native_view_hostable_ = nullptr;
+ } else {
+ [native_view_ setHidden:YES];
+ [native_view_ removeFromSuperview];
}
EnsureNativeViewHasNoChildWidgets(native_view_);
@@ -183,6 +185,10 @@ bool NativeViewHostMac::SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) {
return false;
}
+void NativeViewHostMac::SetHitTestTopInset(int top_inset) {
+ NOTIMPLEMENTED();
+}
+
void NativeViewHostMac::InstallClip(int x, int y, int w, int h) {
NOTIMPLEMENTED();
}
@@ -203,39 +209,40 @@ void NativeViewHostMac::ShowWidget(int x,
int native_h) {
// 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
- // then convert to the containing view.
- NSRect window_rect = NSMakeRect(
- x,
- host_->GetWidget()->GetClientAreaBoundsInScreen().height() - y - h,
- w,
- h);
-
- // 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 =
- [[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));
+ if (native_view_hostable_) {
+ native_view_hostable_->ViewsHostableSetBounds(gfx::Rect(x, y, w, h));
+ native_view_hostable_->ViewsHostableSetVisible(true);
+ } else {
+ // 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 then convert to the containing view.
+ NSRect window_rect = NSMakeRect(
+ x, host_->GetWidget()->GetClientAreaBoundsInScreen().height() - y - h,
+ w, h);
+
+ // 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 = [[native_view_ superview] convertRect:window_rect
+ fromView:nil];
+ [native_view_ setFrame:container_rect];
+ [native_view_ setHidden:NO];
+ }
}
void NativeViewHostMac::HideWidget() {
- [native_view_ setHidden:YES];
-
if (native_view_hostable_)
- native_view_hostable_->OnViewsHostableHide();
+ native_view_hostable_->ViewsHostableSetVisible(false);
+ else
+ [native_view_ setHidden:YES];
}
void NativeViewHostMac::SetFocus() {
- if ([native_view_ acceptsFirstResponder])
- [[native_view_ window] makeFirstResponder:native_view_];
-
- if (native_view_hostable_)
- native_view_hostable_->OnViewsHostableMakeFirstResponder();
+ if (native_view_hostable_) {
+ native_view_hostable_->ViewsHostableMakeFirstResponder();
+ } else {
+ if ([native_view_ acceptsFirstResponder])
+ [[native_view_ window] makeFirstResponder:native_view_];
+ }
}
gfx::NativeView NativeViewHostMac::GetNativeViewContainer() const {
@@ -262,9 +269,14 @@ gfx::NativeCursor NativeViewHostMac::GetCursor(int x, int y) {
}
void NativeViewHostMac::SetVisible(bool visible) {
- [native_view_ setHidden:!visible];
+ if (native_view_hostable_)
+ native_view_hostable_->ViewsHostableSetVisible(visible);
+ else
+ [native_view_ setHidden:!visible];
}
+void NativeViewHostMac::SetParentAccessible(gfx::NativeViewAccessible) {}
+
// 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 3de36c65a96..8ca1ec07eda 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
@@ -26,15 +26,13 @@ class TestViewsHostable : public ui::ViewsHostableView {
private:
// ui::ViewsHostableView:
- void OnViewsHostableAttached(ui::ViewsHostableView::Host* host) override {
+ void ViewsHostableAttach(ui::ViewsHostableView::Host* host) override {
parent_accessibility_element_ = host->GetAccessibilityElement();
}
- void OnViewsHostableDetached() override {
- parent_accessibility_element_ = nil;
- }
- void OnViewsHostableShow(const gfx::Rect& bounds_in_window) override {}
- void OnViewsHostableHide() override {}
- void OnViewsHostableMakeFirstResponder() override {}
+ void ViewsHostableDetach() override { parent_accessibility_element_ = nil; }
+ void ViewsHostableSetBounds(const gfx::Rect& bounds_in_window) override {}
+ void ViewsHostableSetVisible(bool visible) override {}
+ void ViewsHostableMakeFirstResponder() override {}
id parent_accessibility_element_ = nil;
};
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 acd9b2fbd5d..d43cc710daf 100644
--- a/chromium/ui/views/controls/native/native_view_host_wrapper.h
+++ b/chromium/ui/views/controls/native/native_view_host_wrapper.h
@@ -46,6 +46,10 @@ class NativeViewHostWrapper {
// success or false if the platform doesn't support the operation.
virtual bool SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) = 0;
+ // Sets the height of the top region where gfx::NativeView shouldn't be
+ // targeted.
+ virtual void SetHitTestTopInset(int top_inset) = 0;
+
// Installs a clip on the gfx::NativeView. These values are in the coordinate
// space of the Widget, so if this method is called from ShowWidget
// then the values need to be translated.
@@ -95,6 +99,10 @@ class NativeViewHostWrapper {
// or clipping of the view.
virtual void SetVisible(bool visible) = 0;
+ // Pass the parent accessible object to the native view so that it can return
+ // this value when querying its parent accessible.
+ virtual void SetParentAccessible(gfx::NativeViewAccessible) = 0;
+
// Creates a platform-specific instance of an object implementing this
// interface.
static NativeViewHostWrapper* CreateWrapper(NativeViewHost* host);
diff --git a/chromium/ui/views/controls/prefix_selector.cc b/chromium/ui/views/controls/prefix_selector.cc
index 98aab8c61c7..fe8decc9a68 100644
--- a/chromium/ui/views/controls/prefix_selector.cc
+++ b/chromium/ui/views/controls/prefix_selector.cc
@@ -112,12 +112,12 @@ bool PrefixSelector::GetCompositionTextRange(gfx::Range* range) const {
return false;
}
-bool PrefixSelector::GetSelectionRange(gfx::Range* range) const {
+bool PrefixSelector::GetEditableSelectionRange(gfx::Range* range) const {
*range = gfx::Range();
return false;
}
-bool PrefixSelector::SetSelectionRange(const gfx::Range& range) {
+bool PrefixSelector::SetEditableSelectionRange(const gfx::Range& range) {
return false;
}
diff --git a/chromium/ui/views/controls/prefix_selector.h b/chromium/ui/views/controls/prefix_selector.h
index 801c9112b73..de9caa39616 100644
--- a/chromium/ui/views/controls/prefix_selector.h
+++ b/chromium/ui/views/controls/prefix_selector.h
@@ -55,8 +55,8 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
FocusReason GetFocusReason() const override;
bool GetTextRange(gfx::Range* range) const override;
bool GetCompositionTextRange(gfx::Range* range) const override;
- bool GetSelectionRange(gfx::Range* range) const override;
- bool SetSelectionRange(const gfx::Range& range) override;
+ bool GetEditableSelectionRange(gfx::Range* range) const override;
+ bool SetEditableSelectionRange(const gfx::Range& range) override;
bool DeleteRange(const gfx::Range& range) override;
bool GetTextFromRange(const gfx::Range& range,
base::string16* text) const override;
diff --git a/chromium/ui/views/controls/progress_bar.cc b/chromium/ui/views/controls/progress_bar.cc
index 2a5bbfd9a64..d252128ff52 100644
--- a/chromium/ui/views/controls/progress_bar.cc
+++ b/chromium/ui/views/controls/progress_bar.cc
@@ -129,10 +129,8 @@ SkColor ProgressBar::GetForegroundColor() const {
}
SkColor ProgressBar::GetBackgroundColor() const {
- if (background_color_)
- return background_color_.value();
-
- return color_utils::BlendTowardOppositeLuma(GetForegroundColor(), 0xCC);
+ return background_color_.value_or(
+ color_utils::BlendTowardMaxContrast(GetForegroundColor(), 0xCC));
}
void ProgressBar::AnimationProgressed(const gfx::Animation* animation) {
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index cb3a4c981e8..439d6742aa0 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -318,11 +318,6 @@ class WidgetScrollViewTest : public test::WidgetTest,
quit_closure_.Run();
quit_closure_.Reset();
}
- void OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) override {}
- void OnCompositingEnded(ui::Compositor* compositor) override {}
- void OnCompositingChildResizing(ui::Compositor* compositor) override {}
- void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
Widget* widget_ = nullptr;
diff --git a/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm b/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
index 05431a33382..0659d09ce28 100644
--- a/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
+++ b/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
@@ -5,6 +5,7 @@
#import "ui/views/controls/scrollbar/cocoa_scroll_bar.h"
#import "base/mac/sdk_forward_declarations.h"
+#include "base/stl_util.h"
#include "cc/paint/paint_shader.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
@@ -259,7 +260,7 @@ void CocoaScrollBar::OnPaint(gfx::Canvas* canvas) {
cc::PaintFlags gradient;
gradient.setShader(cc::PaintShader::MakeLinearGradient(
gradient_bounds, kScrollerTrackGradientColors, nullptr,
- arraysize(kScrollerTrackGradientColors), SkShader::kClamp_TileMode));
+ base::size(kScrollerTrackGradientColors), SkShader::kClamp_TileMode));
canvas->DrawRect(track_rect, gradient);
// Draw the inner border: top if horizontal, left if vertical.
diff --git a/chromium/ui/views/controls/scrollbar/scroll_bar_views.cc b/chromium/ui/views/controls/scrollbar/scroll_bar_views.cc
index 667eee0e1e1..c7f1a750790 100644
--- a/chromium/ui/views/controls/scrollbar/scroll_bar_views.cc
+++ b/chromium/ui/views/controls/scrollbar/scroll_bar_views.cc
@@ -7,7 +7,6 @@
#include "base/logging.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/path.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/focusable_border.h"
#include "ui/views/controls/scrollbar/base_scroll_bar_button.h"
diff --git a/chromium/ui/views/controls/styled_label_unittest.cc b/chromium/ui/views/controls/styled_label_unittest.cc
index 1d218215e66..90dc1c14a2f 100644
--- a/chromium/ui/views/controls/styled_label_unittest.cc
+++ b/chromium/ui/views/controls/styled_label_unittest.cc
@@ -378,19 +378,19 @@ TEST_F(StyledLabelTest, StyledRangeTextStyleBold) {
}
TEST_F(StyledLabelTest, Color) {
- const std::string text_red("RED");
+ const std::string text_blue("BLUE");
const std::string text_link("link");
const std::string text("word");
- InitStyledLabel(text_red + text_link + text);
+ InitStyledLabel(text_blue + text_link + text);
- StyledLabel::RangeStyleInfo style_info_red;
- style_info_red.override_color = SK_ColorRED;
- styled()->AddStyleRange(gfx::Range(0u, text_red.size()), style_info_red);
+ StyledLabel::RangeStyleInfo style_info_blue;
+ style_info_blue.override_color = SK_ColorBLUE;
+ styled()->AddStyleRange(gfx::Range(0u, text_blue.size()), style_info_blue);
StyledLabel::RangeStyleInfo style_info_link =
StyledLabel::RangeStyleInfo::CreateForLink();
styled()->AddStyleRange(
- gfx::Range(text_red.size(), text_red.size() + text_link.size()),
+ gfx::Range(text_blue.size(), text_blue.size() + text_link.size()),
style_info_link);
styled()->SetBounds(0, 0, 1000, 1000);
@@ -413,7 +413,7 @@ TEST_F(StyledLabelTest, Color) {
container->AddChildView(link);
const SkColor kDefaultLinkColor = link->enabled_color();
- EXPECT_EQ(SK_ColorRED,
+ EXPECT_EQ(SK_ColorBLUE,
static_cast<Label*>(styled()->child_at(0))->enabled_color());
EXPECT_EQ(kDefaultLinkColor,
static_cast<Label*>(styled()->child_at(1))->enabled_color());
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 881e4df535d..e7fd2b8c789 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -383,6 +383,13 @@ void MdTab::OnFocus() {
ui::NativeTheme::kColorId_FocusedBorderColor),
0x66)));
}
+
+ // When the tab gains focus, send an accessibility event indicating that the
+ // contents are focused. When the tab loses focus, whichever new View ends up
+ // with focus will send an ax::mojom::Event::kFocus of its own, so there's no
+ // need to send one in OnBlur().
+ if (contents())
+ contents()->NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true);
SchedulePaint();
}
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 8f08e724af2..f2c79eda6c3 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
@@ -13,6 +13,11 @@
#include "ui/views/widget/widget.h"
#import "testing/gtest_mac.h"
+// This file uses the deprecated NSObject accessibility API - see
+// https://crbug.com/921109.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
namespace views {
namespace test {
@@ -163,3 +168,5 @@ TEST_F(TabbedPaneAccessibilityMacTest, WritableValue) {
} // namespace test
} // namespace views
+
+#pragma clang diagnostic pop
diff --git a/chromium/ui/views/controls/table/table_header.cc b/chromium/ui/views/controls/table/table_header.cc
index 8c5b20fdfe8..49641947cec 100644
--- a/chromium/ui/views/controls/table/table_header.cc
+++ b/chromium/ui/views/controls/table/table_header.cc
@@ -22,19 +22,22 @@ namespace views {
namespace {
-const int kVerticalPadding = 4;
-
// The minimum width we allow a column to go down to.
-const int kMinColumnWidth = 10;
+constexpr int kMinColumnWidth = 10;
+
+// Amount that a column is resized when using the keyboard.
+constexpr int kResizeKeyboardAmount = 5;
+
+constexpr int kVerticalPadding = 4;
// Distace from edge columns can be resized by.
-const int kResizePadding = 5;
+constexpr int kResizePadding = 5;
// Amount of space above/below the separator.
-const int kSeparatorPadding = 4;
+constexpr int kSeparatorPadding = 4;
// Size of the sort indicator (doesn't include padding).
-const int kSortIndicatorSize = 8;
+constexpr int kSortIndicatorSize = 8;
} // namespace
@@ -231,6 +234,29 @@ void TableHeader::OnNativeThemeChanged(const ui::NativeTheme* theme) {
theme->GetSystemColor(ui::NativeTheme::kColorId_TableHeaderBackground)));
}
+void TableHeader::ResizeColumnViaKeyboard(
+ int index,
+ TableView::AdvanceDirection direction) {
+ DCHECK_GE(index, 0);
+ const TableView::VisibleColumn& column = table_->GetVisibleColumn(index);
+ const int needed_for_title =
+ gfx::GetStringWidth(column.column.title, font_list_) +
+ 2 * kHorizontalPadding;
+
+ int new_width = column.width;
+ switch (direction) {
+ case TableView::ADVANCE_INCREMENT:
+ new_width += kResizeKeyboardAmount;
+ break;
+ case TableView::ADVANCE_DECREMENT:
+ new_width -= kResizeKeyboardAmount;
+ break;
+ }
+
+ table_->SetVisibleColumnWidth(
+ index, std::max({kMinColumnWidth, needed_for_title, new_width}));
+}
+
bool TableHeader::StartResize(const ui::LocatedEvent& event) {
if (is_resizing())
return false;
diff --git a/chromium/ui/views/controls/table/table_header.h b/chromium/ui/views/controls/table/table_header.h
index a7d2870ddae..74b1dbb5c95 100644
--- a/chromium/ui/views/controls/table/table_header.h
+++ b/chromium/ui/views/controls/table/table_header.h
@@ -7,13 +7,12 @@
#include "base/macros.h"
#include "ui/gfx/font_list.h"
+#include "ui/views/controls/table/table_view.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
namespace views {
-class TableView;
-
// Views used to render the header for the table.
class VIEWS_EXPORT TableHeader : public views::View {
public:
@@ -31,6 +30,9 @@ class VIEWS_EXPORT TableHeader : public views::View {
const gfx::FontList& font_list() const { return font_list_; }
+ void ResizeColumnViaKeyboard(int index,
+ TableView::AdvanceDirection direction);
+
// views::View overrides.
void Layout() override;
void OnPaint(gfx::Canvas* canvas) override;
diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc
index c4325de2745..a2132f6c93b 100644
--- a/chromium/ui/views/controls/table/table_view.cc
+++ b/chromium/ui/views/controls/table/table_view.cc
@@ -5,31 +5,43 @@
#include "ui/views/controls/table/table_view.h"
#include <stddef.h>
+#include <stdint.h>
#include <algorithm>
#include <map>
#include <utility>
#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/i18n/rtl.h"
-#include "base/strings/string_util.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "cc/paint/paint_flags.h"
+#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/text_utils.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/accessibility/ax_virtual_view.h"
+#include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/table/table_grouper.h"
#include "ui/views/controls/table/table_header.h"
#include "ui/views/controls/table/table_utils.h"
#include "ui/views/controls/table/table_view_observer.h"
#include "ui/views/layout/layout_provider.h"
+#include "ui/views/style/platform_style.h"
#include "ui/views/style/typography.h"
+#include "ui/views/view_properties.h"
namespace views {
@@ -135,7 +147,8 @@ TableView::TableView(ui::TableModel* model,
bool single_selection)
: model_(NULL),
columns_(columns),
- header_(NULL),
+ active_visible_column_index_(-1),
+ header_(nullptr),
table_type_(table_type),
single_selection_(single_selection),
select_on_remove_(true),
@@ -155,9 +168,12 @@ TableView::TableView(ui::TableModel* model,
visible_column.column = columns[i];
visible_columns_.push_back(visible_column);
}
+
// Always focusable, even on Mac (consistent with NSTableView).
SetFocusBehavior(FocusBehavior::ALWAYS);
SetModel(model);
+ if (model_)
+ UpdateVirtualAccessibilityChildren();
}
TableView::~TableView() {
@@ -220,6 +236,11 @@ void TableView::SetColumnVisibility(int id, bool is_visible) {
for (size_t i = 0; i < visible_columns_.size(); ++i) {
if (visible_columns_[i].column.id == id) {
visible_columns_.erase(visible_columns_.begin() + i);
+ if (active_visible_column_index_ >=
+ static_cast<int>(visible_columns_.size())) {
+ SetActiveVisibleColumnIndex(
+ static_cast<int>(visible_columns_.size()) - 1);
+ }
break;
}
}
@@ -229,6 +250,7 @@ void TableView::SetColumnVisibility(int id, bool is_visible) {
SchedulePaint();
if (header_)
header_->SchedulePaint();
+ UpdateVirtualAccessibilityChildren();
}
void TableView::ToggleSortOrder(int visible_column_index) {
@@ -284,6 +306,32 @@ bool TableView::HasColumn(int id) const {
return false;
}
+bool TableView::HasFocusIndicator() const {
+ int active_row = selection_model_.active();
+ return active_row != ui::ListSelectionModel::kUnselectedIndex &&
+ active_visible_column_index_ !=
+ ui::ListSelectionModel::kUnselectedIndex;
+}
+
+void TableView::ResetFocusIndicator() {
+ if (!PlatformStyle::kTableViewSupportsKeyboardNavigationByCell)
+ return;
+
+ if (HasFocusIndicator()) {
+ // Draw a focus indicator around the active column.
+ focus_ring_ = FocusRing::Install(this);
+ const gfx::Rect cell_bounds(GetCellBounds(
+ ModelToView(selection_model_.active()), active_visible_column_index_));
+ auto path = std::make_unique<SkPath>();
+ path->addRect(gfx::RectToSkRect(cell_bounds));
+ SetProperty(views::kHighlightPathKey, path.release());
+ focus_ring_->SchedulePaint();
+ } else {
+ ClearProperty(views::kHighlightPathKey);
+ focus_ring_.reset();
+ }
+}
+
const TableView::VisibleColumn& TableView::GetVisibleColumn(int index) {
DCHECK(index >= 0 && index < static_cast<int>(visible_columns_.size()));
return visible_columns_[index];
@@ -344,6 +392,9 @@ void TableView::Layout() {
height = std::max(parent()->height(), height);
}
SetBounds(x(), y(), width, height);
+
+ if (focus_ring_)
+ focus_ring_->Layout();
}
const char* TableView::GetClassName() const {
@@ -385,16 +436,77 @@ bool TableView::OnKeyPressed(const ui::KeyEvent& event) {
return true;
case ui::VKEY_UP:
+#if defined(OS_MACOSX)
+ if (event.IsAltDown()) {
+ if (RowCount())
+ SelectByViewIndex(0);
+ } else {
+ AdvanceSelection(ADVANCE_DECREMENT);
+ }
+#else
AdvanceSelection(ADVANCE_DECREMENT);
+#endif
return true;
case ui::VKEY_DOWN:
+#if defined(OS_MACOSX)
+ if (event.IsAltDown()) {
+ if (RowCount())
+ SelectByViewIndex(RowCount() - 1);
+ } else {
+ AdvanceSelection(ADVANCE_INCREMENT);
+ }
+#else
AdvanceSelection(ADVANCE_INCREMENT);
+#endif
return true;
+ case ui::VKEY_LEFT:
+ if (PlatformStyle::kTableViewSupportsKeyboardNavigationByCell) {
+ if (IsCmdOrCtrl(event)) {
+ if (active_visible_column_index_ != -1 && header_) {
+ const AdvanceDirection direction =
+ base::i18n::IsRTL() ? ADVANCE_INCREMENT : ADVANCE_DECREMENT;
+ header_->ResizeColumnViaKeyboard(active_visible_column_index_,
+ direction);
+ ResetFocusIndicator();
+ }
+ } else {
+ AdvanceActiveVisibleColumn(ADVANCE_DECREMENT);
+ }
+ return true;
+ }
+ break;
+
+ case ui::VKEY_RIGHT:
+ if (PlatformStyle::kTableViewSupportsKeyboardNavigationByCell) {
+ if (IsCmdOrCtrl(event)) {
+ if (active_visible_column_index_ != -1 && header_) {
+ const AdvanceDirection direction =
+ base::i18n::IsRTL() ? ADVANCE_DECREMENT : ADVANCE_INCREMENT;
+ header_->ResizeColumnViaKeyboard(active_visible_column_index_,
+ direction);
+ ResetFocusIndicator();
+ }
+ } else {
+ AdvanceActiveVisibleColumn(ADVANCE_INCREMENT);
+ }
+ return true;
+ }
+ break;
+
+ case ui::VKEY_SPACE:
+ if (PlatformStyle::kTableViewSupportsKeyboardNavigationByCell &&
+ active_visible_column_index_ != -1) {
+ ToggleSortOrder(active_visible_column_index_);
+ return true;
+ }
+ break;
+
default:
break;
}
+
if (observer_)
observer_->OnKeyDown(event.key_code());
return false;
@@ -449,36 +561,78 @@ bool TableView::GetTooltipTextOrigin(const gfx::Point& p,
}
void TableView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
- // TODO(aleventhal) Needs work, see https://crbug.com/811277.
- node_data->role = ax::mojom::Role::kTable;
+ node_data->role = ax::mojom::Role::kListGrid;
+ node_data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ GetClassName());
node_data->SetRestriction(ax::mojom::Restriction::kReadOnly);
- node_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize, RowCount());
-
- if (selection_model_.active() != ui::ListSelectionModel::kUnselectedIndex) {
- // Get information about the active item, this is not the same as the set
- // of selected items (of which there could be more than one).
- node_data->role = ax::mojom::Role::kRow;
- node_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
- selection_model_.active());
- node_data->AddBoolAttribute(
- ax::mojom::BoolAttribute::kSelected,
- selection_model_.IsSelected(selection_model_.active()));
-
- // Generate accessible name from column headers and selected cell text.
- std::vector<base::string16> name_parts;
- for (const VisibleColumn& visible_column : visible_columns_) {
- base::string16 value = model_->GetText(
- selection_model_.active(), visible_column.column.id);
- if (!value.empty()) {
- name_parts.push_back(visible_column.column.title);
- name_parts.push_back(value);
- }
+ node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kActivate);
+ // Subclasses should overwrite the name with the control's associated label.
+ node_data->SetNameExplicitlyEmpty();
+
+ node_data->AddIntAttribute(ax::mojom::IntAttribute::kTableRowCount,
+ static_cast<int32_t>(RowCount()));
+ node_data->AddIntAttribute(ax::mojom::IntAttribute::kTableColumnCount,
+ static_cast<int32_t>(visible_columns_.size()));
+ node_data->relative_bounds.bounds = gfx::RectF(GetVisibleBounds());
+}
+
+bool TableView::HandleAccessibleAction(const ui::AXActionData& action_data) {
+ if (!RowCount())
+ return false;
+
+ int active_row = selection_model_.active();
+ if (active_row == ui::ListSelectionModel::kUnselectedIndex)
+ active_row = ModelToView(0);
+
+ switch (action_data.action) {
+ case ax::mojom::Action::kDoDefault:
+ RequestFocus();
+ SelectByViewIndex(ModelToView(active_row));
+ if (observer_)
+ observer_->OnDoubleClick();
+ break;
+
+ case ax::mojom::Action::kFocus:
+ RequestFocus();
+ // Setting focus should not affect the current selection.
+ if (selection_model_.empty())
+ SelectByViewIndex(0);
+ break;
+
+ case ax::mojom::Action::kScrollRight: {
+ const AdvanceDirection direction =
+ base::i18n::IsRTL() ? ADVANCE_DECREMENT : ADVANCE_INCREMENT;
+ AdvanceActiveVisibleColumn(direction);
+ break;
}
- node_data->SetName(base::JoinString(name_parts, base::ASCIIToUTF16(", ")));
- } else {
- // Name requires a selection.
- node_data->SetNameExplicitlyEmpty();
+
+ case ax::mojom::Action::kScrollLeft: {
+ const AdvanceDirection direction =
+ base::i18n::IsRTL() ? ADVANCE_INCREMENT : ADVANCE_DECREMENT;
+ AdvanceActiveVisibleColumn(direction);
+ break;
+ }
+
+ case ax::mojom::Action::kScrollToMakeVisible:
+ ScrollRectToVisible(GetRowBounds(ModelToView(active_row)));
+ break;
+
+ case ax::mojom::Action::kSetSelection:
+ // TODO(nektar): Retrieve the anchor and focus nodes once AXVirtualView is
+ // implemented in this class.
+ SelectByViewIndex(active_row);
+ break;
+
+ case ax::mojom::Action::kShowContextMenu:
+ ShowContextMenu(GetBoundsInScreen().CenterPoint(),
+ ui::MENU_SOURCE_KEYBOARD);
+ break;
+
+ default:
+ return false;
}
+
+ return true;
}
void TableView::OnModelChanged() {
@@ -525,6 +679,7 @@ void TableView::OnItemsRemoved(int start, int length) {
selection_model_.set_active(FirstSelectedRow());
if (!selection_model_.empty() && selection_model_.anchor() == -1)
selection_model_.set_anchor(FirstSelectedRow());
+ NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
if (observer_)
observer_->OnSelectionChanged();
}
@@ -655,7 +810,8 @@ void TableView::OnFocus() {
scroll_view->SetHasFocusIndicator(true);
SchedulePaintForSelection();
- NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true);
+ ResetFocusIndicator();
+ UpdateAccessibilityFocus();
}
void TableView::OnBlur() {
@@ -663,6 +819,8 @@ void TableView::OnBlur() {
if (scroll_view)
scroll_view->SetHasFocusIndicator(false);
SchedulePaintForSelection();
+ ResetFocusIndicator();
+ UpdateAccessibilityFocus();
}
int TableView::GetCellMargin() const {
@@ -679,6 +837,7 @@ void TableView::NumRowsChanged() {
SortItemsAndUpdateMapping();
PreferredSizeChanged();
SchedulePaint();
+ UpdateVirtualAccessibilityChildren();
}
void TableView::SortItemsAndUpdateMapping() {
@@ -706,6 +865,7 @@ void TableView::SortItemsAndUpdateMapping() {
model_->ClearCollator();
}
SchedulePaint();
+ UpdateVirtualAccessibilityChildren();
}
int TableView::CompareRows(int model_row1, int model_row2) {
@@ -754,6 +914,7 @@ void TableView::CreateHeaderIfNecessary() {
return;
header_ = new TableHeader(this);
+ UpdateVirtualAccessibilityChildren();
}
void TableView::UpdateVisibleColumnSizes() {
@@ -846,6 +1007,47 @@ ui::TableColumn TableView::FindColumnByID(int id) const {
return ui::TableColumn();
}
+void TableView::AdvanceActiveVisibleColumn(AdvanceDirection direction) {
+ if (visible_columns_.empty()) {
+ SetActiveVisibleColumnIndex(-1);
+ return;
+ }
+
+ if (active_visible_column_index_ == -1) {
+ if (selection_model_.active() == -1)
+ SelectByViewIndex(0);
+ SetActiveVisibleColumnIndex(0);
+ return;
+ }
+
+ if (direction == ADVANCE_DECREMENT) {
+ SetActiveVisibleColumnIndex(std::max(0, active_visible_column_index_ - 1));
+ } else {
+ SetActiveVisibleColumnIndex(
+ std::min(static_cast<int>(visible_columns_.size()) - 1,
+ active_visible_column_index_ + 1));
+ }
+}
+
+int TableView::GetActiveVisibleColumnIndex() const {
+ return active_visible_column_index_;
+}
+
+void TableView::SetActiveVisibleColumnIndex(int index) {
+ if (active_visible_column_index_ == index)
+ return;
+ active_visible_column_index_ = index;
+
+ if (selection_model_.active() != ui::ListSelectionModel::kUnselectedIndex &&
+ active_visible_column_index_ != -1) {
+ ScrollRectToVisible(GetCellBounds(ModelToView(selection_model_.active()),
+ active_visible_column_index_));
+ }
+
+ ResetFocusIndicator();
+ UpdateAccessibilityFocus();
+}
+
void TableView::SelectByViewIndex(int view_index) {
ui::ListSelectionModel new_selection;
if (view_index != -1) {
@@ -875,12 +1077,18 @@ void TableView::SetSelectionModel(ui::ListSelectionModel new_selection) {
vis_rect.set_y(start_y);
vis_rect.set_height(end_y - start_y);
ScrollRectToVisible(vis_rect);
+
+ if (active_visible_column_index_ == -1)
+ SetActiveVisibleColumnIndex(0);
+ } else {
+ SetActiveVisibleColumnIndex(-1);
}
+ ResetFocusIndicator();
+ UpdateAccessibilityFocus();
+ NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
if (observer_)
observer_->OnSelectionChanged();
-
- NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true);
}
void TableView::AdvanceSelection(AdvanceDirection direction) {
@@ -995,4 +1203,234 @@ bool TableView::GetTooltipImpl(const gfx::Point& location,
return true;
}
+void TableView::UpdateVirtualAccessibilityChildren() {
+ GetViewAccessibility().RemoveAllVirtualChildViews();
+ if (!RowCount() || visible_columns_.empty()) {
+ NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, true);
+ return;
+ }
+
+ const base::Optional<int> primary_sorted_column_id =
+ sort_descriptors().empty()
+ ? base::nullopt
+ : base::make_optional(sort_descriptors()[0].column_id);
+ if (header_) {
+ auto ax_header = std::make_unique<AXVirtualView>();
+ ui::AXNodeData& header_data = ax_header->GetCustomData();
+ header_data.role = ax::mojom::Role::kRow;
+ header_data.relative_bounds.bounds =
+ gfx::RectF(header_->GetVisibleBounds());
+
+ for (size_t visible_column_index = 0;
+ visible_column_index < visible_columns_.size();
+ ++visible_column_index) {
+ const VisibleColumn& visible_column =
+ visible_columns_[visible_column_index];
+ const ui::TableColumn column = visible_column.column;
+ auto ax_cell = std::make_unique<AXVirtualView>();
+ ui::AXNodeData& cell_data = ax_cell->GetCustomData();
+ cell_data.role = ax::mojom::Role::kColumnHeader;
+ cell_data.SetName(column.title);
+ gfx::Rect header_cell_bounds(visible_column.x, header_->y(),
+ visible_column.width, header_->height());
+ cell_data.relative_bounds.bounds = gfx::RectF(header_cell_bounds);
+ cell_data.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex,
+ static_cast<int32_t>(visible_column_index));
+ cell_data.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan,
+ 1);
+ if (base::i18n::IsRTL())
+ cell_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+
+ auto sort_direction = ax::mojom::SortDirection::kUnsorted;
+ if (column.sortable && primary_sorted_column_id.has_value() &&
+ column.id == primary_sorted_column_id.value()) {
+ DCHECK(!sort_descriptors().empty());
+ if (sort_descriptors()[0].ascending)
+ sort_direction = ax::mojom::SortDirection::kAscending;
+ else
+ sort_direction = ax::mojom::SortDirection::kDescending;
+ }
+ cell_data.AddIntAttribute(ax::mojom::IntAttribute::kSortDirection,
+ static_cast<int32_t>(sort_direction));
+
+ ax_header->AddChildView(std::move(ax_cell));
+ }
+
+ GetViewAccessibility().AddVirtualChildView(std::move(ax_header));
+ }
+
+ for (int view_index = 0; view_index < RowCount(); ++view_index) {
+ const int model_index = ViewToModel(view_index);
+ auto ax_row = std::make_unique<AXVirtualView>();
+ ui::AXNodeData& row_data = ax_row->GetCustomData();
+ row_data.role = ax::mojom::Role::kRow;
+
+ if (!PlatformStyle::kTableViewSupportsKeyboardNavigationByCell) {
+ row_data.AddState(ax::mojom::State::kFocusable);
+ // When navigating using up / down cursor keys on the Mac, we read the
+ // contents of the first cell. If the user needs to explore additional
+ // cells, they can use VoiceOver shortcuts.
+ row_data.SetName(
+ model_->GetText(model_index, visible_columns_[0].column.id));
+ }
+
+ row_data.SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kSelect);
+ row_data.AddIntAttribute(ax::mojom::IntAttribute::kTableRowIndex,
+ static_cast<int32_t>(view_index));
+ gfx::Rect row_bounds = GetRowBounds(view_index);
+ row_data.relative_bounds.bounds = gfx::RectF(row_bounds);
+ if (!single_selection_)
+ row_data.AddState(ax::mojom::State::kMultiselectable);
+
+ base::RepeatingCallback<void(const View&, ui::AXNodeData*)> row_callback =
+ base::BindRepeating(
+ [](const int model_index, const gfx::Rect& row_bounds,
+ const View& view, ui::AXNodeData* data) {
+ auto& table = static_cast<const TableView&>(view);
+ if (!table.GetVisibleBounds().Intersects(row_bounds))
+ data->AddState(ax::mojom::State::kInvisible);
+ if (table.selection_model().IsSelected(model_index)) {
+ data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
+ true);
+ }
+ },
+ model_index, row_bounds);
+ ax_row->SetPopulateDataCallback(std::move(row_callback));
+
+ for (size_t visible_column_index = 0;
+ visible_column_index < visible_columns_.size();
+ ++visible_column_index) {
+ const VisibleColumn& visible_column =
+ visible_columns_[visible_column_index];
+ const ui::TableColumn column = visible_column.column;
+ auto ax_cell = std::make_unique<AXVirtualView>();
+ ui::AXNodeData& cell_data = ax_cell->GetCustomData();
+ cell_data.role = ax::mojom::Role::kCell;
+ if (PlatformStyle::kTableViewSupportsKeyboardNavigationByCell)
+ cell_data.AddState(ax::mojom::State::kFocusable);
+ gfx::Rect cell_bounds = GetCellBounds(view_index, visible_column_index);
+ cell_data.relative_bounds.bounds = gfx::RectF(cell_bounds);
+
+ cell_data.AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex,
+ static_cast<int32_t>(view_index));
+ cell_data.AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowSpan, 1);
+ cell_data.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex,
+ static_cast<int32_t>(visible_column_index));
+ cell_data.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan,
+ 1);
+
+ cell_data.SetName(model_->GetText(model_index, column.id));
+ if (base::i18n::IsRTL())
+ cell_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+
+ auto sort_direction = ax::mojom::SortDirection::kUnsorted;
+ if (column.sortable && primary_sorted_column_id.has_value() &&
+ column.id == primary_sorted_column_id.value()) {
+ DCHECK(!sort_descriptors().empty());
+ if (sort_descriptors()[0].ascending)
+ sort_direction = ax::mojom::SortDirection::kAscending;
+ else
+ sort_direction = ax::mojom::SortDirection::kDescending;
+ }
+ cell_data.AddIntAttribute(ax::mojom::IntAttribute::kSortDirection,
+ static_cast<int32_t>(sort_direction));
+
+ base::RepeatingCallback<void(const View&, ui::AXNodeData*)>
+ cell_callback = base::BindRepeating(
+ [](const int model_index, const size_t visible_column_index,
+ const gfx::Rect& cell_bounds, const View& view,
+ ui::AXNodeData* data) {
+ auto& table = static_cast<const TableView&>(view);
+ if (!table.GetVisibleBounds().Intersects(cell_bounds))
+ data->AddState(ax::mojom::State::kInvisible);
+ if (PlatformStyle::kTableViewSupportsKeyboardNavigationByCell &&
+ static_cast<const int>(visible_column_index) ==
+ table.GetActiveVisibleColumnIndex()) {
+ if (table.selection_model().IsSelected(model_index)) {
+ data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
+ true);
+ }
+ }
+ },
+ model_index, visible_column_index, cell_bounds);
+ ax_cell->SetPopulateDataCallback(std::move(cell_callback));
+
+ ax_row->AddChildView(std::move(ax_cell));
+ }
+
+ GetViewAccessibility().AddVirtualChildView(std::move(ax_row));
+ }
+
+ NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, true);
+}
+
+void TableView::UpdateAccessibilityFocus() {
+ if (!HasFocus())
+ return;
+
+ if (selection_model_.active() == ui::ListSelectionModel::kUnselectedIndex ||
+ active_visible_column_index_ == -1) {
+ GetViewAccessibility().OverrideFocus(nullptr);
+ NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true);
+ return;
+ }
+
+ int active_row = ModelToView(selection_model_.active());
+ if (!PlatformStyle::kTableViewSupportsKeyboardNavigationByCell) {
+ AXVirtualView* ax_row = GetVirtualAccessibilityRow(active_row);
+ if (ax_row) {
+ GetViewAccessibility().OverrideFocus(ax_row);
+ ax_row->NotifyAccessibilityEvent(ax::mojom::Event::kFocus);
+ }
+ } else {
+ AXVirtualView* ax_cell =
+ GetVirtualAccessibilityCell(active_row, active_visible_column_index_);
+ if (ax_cell) {
+ GetViewAccessibility().OverrideFocus(ax_cell);
+ ax_cell->NotifyAccessibilityEvent(ax::mojom::Event::kFocus);
+ }
+ }
+}
+
+AXVirtualView* TableView::GetVirtualAccessibilityRow(int row) {
+ DCHECK_GE(row, 0);
+ DCHECK_LT(row, RowCount());
+ if (header_)
+ row += 1;
+ if (row < GetViewAccessibility().virtual_child_count()) {
+ AXVirtualView* ax_row = GetViewAccessibility().virtual_child_at(row);
+ DCHECK(ax_row);
+ DCHECK_EQ(ax_row->GetData().role, ax::mojom::Role::kRow);
+ return ax_row;
+ }
+ NOTREACHED() << "|row| not found. Did you forget to call "
+ "UpdateVirtualAccessibilityChildren()?";
+ return nullptr;
+}
+
+AXVirtualView* TableView::GetVirtualAccessibilityCell(
+ int row,
+ int visible_column_index) {
+ AXVirtualView* ax_row = GetVirtualAccessibilityRow(row);
+ if (!ax_row) {
+ NOTREACHED() << "|row| not found. Did you forget to call "
+ "UpdateVirtualAccessibilityChildren()?";
+ return nullptr;
+ }
+ for (int i = 0; i < ax_row->GetChildCount(); ++i) {
+ AXVirtualView* ax_cell = ax_row->child_at(i);
+ DCHECK(ax_cell);
+ DCHECK(ax_cell->GetData().role == ax::mojom::Role::kColumnHeader ||
+ ax_cell->GetData().role == ax::mojom::Role::kCell);
+ if (ax_cell->GetData().GetIntAttribute(
+ ax::mojom::IntAttribute::kTableCellColumnIndex) ==
+ visible_column_index) {
+ return ax_cell;
+ }
+ }
+ NOTREACHED() << "|visible_column_index| not found. Did you forget to call "
+ "UpdateVirtualAccessibilityChildren()?";
+ return nullptr;
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/table/table_view.h b/chromium/ui/views/controls/table/table_view.h
index eca7e3ed55f..d4cbc6bb4c1 100644
--- a/chromium/ui/views/controls/table/table_view.h
+++ b/chromium/ui/views/controls/table/table_view.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_
#define UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_
+#include <memory>
#include <vector>
#include "base/macros.h"
@@ -12,9 +13,17 @@
#include "ui/base/models/table_model.h"
#include "ui/base/models/table_model_observer.h"
#include "ui/gfx/font_list.h"
+#include "ui/views/controls/focus_ring.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
+namespace ui {
+
+struct AXActionData;
+struct AXNodeData;
+
+} // namespace ui
+
// A TableView is a view that displays multiple rows with any number of columns.
// TableView is driven by a TableModel. The model returns the contents
// to display. TableModel also has an Observer which is used to notify
@@ -32,6 +41,8 @@
// sort by way of overriding TableModel::CompareValues().
namespace views {
+class AXVirtualView;
+class FocusRing;
struct GroupRange;
class TableGrouper;
class TableHeader;
@@ -54,6 +65,14 @@ class VIEWS_EXPORT TableView
// Internal class name.
static const char kViewClassName[];
+ // Used by AdvanceActiveVisibleColumn(), AdvanceSelection() and
+ // ResizeColumnViaKeyboard() to determine the direction to change the
+ // selection.
+ enum AdvanceDirection {
+ ADVANCE_DECREMENT,
+ ADVANCE_INCREMENT,
+ };
+
// Used to track a visible column. Useful only for the header.
struct VIEWS_EXPORT VisibleColumn {
VisibleColumn();
@@ -132,9 +151,20 @@ class VIEWS_EXPORT TableView
// or not).
bool HasColumn(int id) const;
+ // Returns whether an active row and column have been set.
+ bool HasFocusIndicator() const;
+
+ // Moves the focus ring to its new location if the active cell has changed, or
+ // hides the focus ring if the table is not focused.
+ void ResetFocusIndicator();
+
void set_observer(TableViewObserver* observer) { observer_ = observer; }
TableViewObserver* observer() const { return observer_; }
+ int GetActiveVisibleColumnIndex() const;
+
+ void SetActiveVisibleColumnIndex(int index);
+
const std::vector<VisibleColumn>& visible_columns() const {
return visible_columns_;
}
@@ -181,6 +211,7 @@ class VIEWS_EXPORT TableView
bool GetTooltipTextOrigin(const gfx::Point& p,
gfx::Point* loc) const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+ bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
// ui::TableModelObserver overrides:
void OnModelChanged() override;
@@ -215,13 +246,6 @@ class VIEWS_EXPORT TableView
int max_column;
};
- // Used by AdvanceSelection() to determine the direction to change the
- // selection.
- enum AdvanceDirection {
- ADVANCE_DECREMENT,
- ADVANCE_INCREMENT,
- };
-
// Returns the horizontal margin between the bounds of a cell and its
// contents.
int GetCellMargin() const;
@@ -275,6 +299,10 @@ class VIEWS_EXPORT TableView
// Returns the TableColumn matching the specified id.
ui::TableColumn FindColumnByID(int id) const;
+ // Advances the active visible column (from the active visible column index)
+ // in the specified direction.
+ void AdvanceActiveVisibleColumn(AdvanceDirection direction);
+
// Sets the selection to the specified index (in terms of the view).
void SelectByViewIndex(int view_index);
@@ -307,6 +335,24 @@ class VIEWS_EXPORT TableView
base::string16* tooltip,
gfx::Point* tooltip_origin) const;
+ // Updates a set of accessibility views that expose the visible table contents
+ // to assistive software.
+ void UpdateVirtualAccessibilityChildren();
+
+ // Updates the internal accessibility state and fires the required
+ // accessibility events to indicate to assistive software which row is active
+ // and which cell is focused, if any.
+ void UpdateAccessibilityFocus();
+
+ // Returns the virtual accessibility view corresponding to the specified row.
+ // |row| should be a view index, not a model index.
+ AXVirtualView* GetVirtualAccessibilityRow(int row);
+
+ // Returns the virtual accessibility view corresponding to the specified cell.
+ // |row| should be a view index, not a model index.
+ // |visible_column_index| indexes into |visible_columns_|.
+ AXVirtualView* GetVirtualAccessibilityCell(int row, int visible_column_index);
+
ui::TableModel* model_;
std::vector<ui::TableColumn> columns_;
@@ -315,6 +361,13 @@ class VIEWS_EXPORT TableView
// may contain a subset of |columns_|.
std::vector<VisibleColumn> visible_columns_;
+ // The active visible column. Used for keyboard access to functionality such
+ // as sorting and resizing. -1 if no visible column is active.
+ int active_visible_column_index_;
+
+ // Used to draw a focus indicator around the active cell.
+ std::unique_ptr<FocusRing> focus_ring_;
+
// The header. This is only created if more than one column is specified or
// the first column has a non-empty title.
TableHeader* header_;
diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc
index df04dc1a96e..83e7a21d268 100644
--- a/chromium/ui/views/controls/table/table_view_unittest.cc
+++ b/chromium/ui/views/controls/table/table_view_unittest.cc
@@ -9,13 +9,19 @@
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/text_utils.h"
+#include "ui/views/accessibility/ax_virtual_view.h"
+#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/table/table_grouper.h"
#include "ui/views/controls/table/table_header.h"
#include "ui/views/controls/table/table_view_observer.h"
+#include "ui/views/style/platform_style.h"
#include "ui/views/test/focus_manager_test.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
@@ -42,6 +48,10 @@ class TableViewTestHelper {
return table_->visible_columns().size();
}
+ int GetActiveVisibleColumnIndex() {
+ return table_->GetActiveVisibleColumnIndex();
+ }
+
TableHeader* header() { return table_->header_; }
void SetSelectionModel(const ui::ListSelectionModel& new_selection) {
@@ -50,6 +60,15 @@ class TableViewTestHelper {
const gfx::FontList& font_list() { return table_->font_list_; }
+ AXVirtualView* GetVirtualAccessibilityRow(int row) {
+ return table_->GetVirtualAccessibilityRow(row);
+ }
+
+ AXVirtualView* GetVirtualAccessibilityCell(int row,
+ int visible_column_index) {
+ return table_->GetVirtualAccessibilityCell(row, visible_column_index);
+ }
+
private:
TableView* table_;
@@ -301,9 +320,11 @@ class TableViewTest : public ViewsTestBase {
return result;
}
- void PressKey(ui::KeyboardCode code) {
+ void PressKey(ui::KeyboardCode code) { PressKey(code, ui::EF_NONE); }
+
+ void PressKey(ui::KeyboardCode code, int flags) {
ui::test::EventGenerator generator(GetRootWindow(widget_.get()));
- generator.PressKey(code, ui::EF_NONE);
+ generator.PressKey(code, flags);
}
protected:
@@ -337,6 +358,87 @@ TEST_F(TableViewTest, GetPaintRegion) {
helper_->GetPaintRegion(gfx::Rect(0, 0, 1, table_->height())));
}
+TEST_F(TableViewTest, UpdateVirtualAccessibilityChildren) {
+ const ViewAccessibility& view_accessibility = table_->GetViewAccessibility();
+ ui::AXNodeData data;
+ view_accessibility.GetAccessibleNodeData(&data);
+ EXPECT_EQ(ax::mojom::Role::kListGrid, data.role);
+ EXPECT_TRUE(data.HasState(ax::mojom::State::kFocusable));
+ EXPECT_EQ(ax::mojom::Restriction::kReadOnly, data.GetRestriction());
+ EXPECT_EQ(table_->RowCount(), static_cast<int>(data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableRowCount)));
+ EXPECT_EQ(helper_->visible_col_count(),
+ static_cast<size_t>(data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableColumnCount)));
+
+ // The header takes up another row.
+ ASSERT_EQ(table_->RowCount() + 1, view_accessibility.virtual_child_count());
+ const AXVirtualView* header = view_accessibility.virtual_child_at(0);
+ ASSERT_TRUE(header);
+ EXPECT_EQ(ax::mojom::Role::kRow, header->GetData().role);
+
+ ASSERT_EQ(
+ helper_->visible_col_count(),
+ static_cast<size_t>(const_cast<AXVirtualView*>(header)->GetChildCount()));
+ for (int j = 0; j < static_cast<int>(helper_->visible_col_count()); ++j) {
+ const AXVirtualView* header_cell = header->child_at(j);
+ ASSERT_TRUE(header_cell);
+ const ui::AXNodeData& header_cell_data = header_cell->GetData();
+ EXPECT_EQ(ax::mojom::Role::kColumnHeader, header_cell_data.role);
+ EXPECT_EQ(j, static_cast<int>(header_cell_data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableCellColumnIndex)));
+ }
+
+ for (int i = 1; i < table_->RowCount() + 1; ++i) {
+ const AXVirtualView* row = view_accessibility.virtual_child_at(i);
+ ASSERT_TRUE(row);
+ const ui::AXNodeData& row_data = row->GetData();
+ EXPECT_EQ(ax::mojom::Role::kRow, row_data.role);
+ EXPECT_EQ(i - 1, static_cast<int>(row_data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableRowIndex)));
+
+ ASSERT_EQ(
+ helper_->visible_col_count(),
+ static_cast<size_t>(const_cast<AXVirtualView*>(row)->GetChildCount()));
+ for (int j = 0; j < static_cast<int>(helper_->visible_col_count()); ++j) {
+ const AXVirtualView* cell = row->child_at(j);
+ ASSERT_TRUE(cell);
+ const ui::AXNodeData& cell_data = cell->GetData();
+ EXPECT_EQ(ax::mojom::Role::kCell, cell_data.role);
+ EXPECT_EQ(i - 1, static_cast<int>(cell_data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableCellRowIndex)));
+ EXPECT_EQ(j, static_cast<int>(cell_data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableCellColumnIndex)));
+ }
+ }
+}
+
+TEST_F(TableViewTest, GetVirtualAccessibilityRow) {
+ for (int i = 0; i < table_->RowCount(); ++i) {
+ const AXVirtualView* row = helper_->GetVirtualAccessibilityRow(i);
+ ASSERT_TRUE(row);
+ const ui::AXNodeData& row_data = row->GetData();
+ EXPECT_EQ(ax::mojom::Role::kRow, row_data.role);
+ EXPECT_EQ(i, static_cast<int>(row_data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableRowIndex)));
+ }
+}
+
+TEST_F(TableViewTest, GetVirtualAccessibilityCell) {
+ for (int i = 0; i < table_->RowCount(); ++i) {
+ for (int j = 0; j < static_cast<int>(helper_->visible_col_count()); ++j) {
+ const AXVirtualView* cell = helper_->GetVirtualAccessibilityCell(i, j);
+ ASSERT_TRUE(cell);
+ const ui::AXNodeData& cell_data = cell->GetData();
+ EXPECT_EQ(ax::mojom::Role::kCell, cell_data.role);
+ EXPECT_EQ(i, static_cast<int>(cell_data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableCellRowIndex)));
+ EXPECT_EQ(j, static_cast<int>(cell_data.GetIntAttribute(
+ ax::mojom::IntAttribute::kTableCellColumnIndex)));
+ }
+ }
+}
+
// Verifies SetColumnVisibility().
TEST_F(TableViewTest, ColumnVisibility) {
// Two columns should be visible.
@@ -370,7 +472,7 @@ TEST_F(TableViewTest, ColumnVisibility) {
EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds()));
}
-// Verifies resizing a column works.
+// Verifies resizing a column using the mouse works.
TEST_F(TableViewTest, Resize) {
const int x = table_->GetVisibleColumn(0).width;
EXPECT_NE(0, x);
@@ -402,6 +504,40 @@ TEST_F(TableViewTest, ResizeViaGesture) {
EXPECT_EQ(x - 1, table_->GetVisibleColumn(1).x);
}
+// Verifies resizing a column works with the keyboard.
+// The resize keyboard amount is 5 pixels.
+TEST_F(TableViewTest, ResizeViaKeyboard) {
+ if (!PlatformStyle::kTableViewSupportsKeyboardNavigationByCell)
+ return;
+
+ table_->RequestFocus();
+ const int x = table_->GetVisibleColumn(0).width;
+ EXPECT_NE(0, x);
+
+ // Table starts off with no visible column being active.
+ ASSERT_EQ(-1, helper_->GetActiveVisibleColumnIndex());
+
+ ui::ListSelectionModel new_selection;
+ new_selection.SetSelectedIndex(1);
+ helper_->SetSelectionModel(new_selection);
+ ASSERT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+
+ PressKey(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN);
+ // This should shrink the first column and pull the second column in.
+ EXPECT_EQ(x - 5, table_->GetVisibleColumn(0).width);
+ EXPECT_EQ(x - 5, table_->GetVisibleColumn(1).x);
+
+ PressKey(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
+ // This should restore the columns to their original sizes.
+ EXPECT_EQ(x, table_->GetVisibleColumn(0).width);
+ EXPECT_EQ(x, table_->GetVisibleColumn(1).x);
+
+ PressKey(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
+ // This should expand the first column and push the second column out.
+ EXPECT_EQ(x + 5, table_->GetVisibleColumn(0).width);
+ EXPECT_EQ(x + 5, table_->GetVisibleColumn(1).x);
+}
+
// Verifies resizing a column won't reduce the column width below the width of
// the column's title text.
TEST_F(TableViewTest, ResizeHonorsMinimum) {
@@ -552,7 +688,7 @@ TEST_F(TableViewTest, Sort) {
GetRowsInViewOrderAsString(table_));
}
-// Verfies clicking on the header sorts.
+// Verifies clicking on the header sorts.
TEST_F(TableViewTest, SortOnMouse) {
EXPECT_TRUE(table_->sort_descriptors().empty());
@@ -568,6 +704,43 @@ TEST_F(TableViewTest, SortOnMouse) {
EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
}
+// Verifies that pressing the space bar when a particular visible column is
+// active will sort by that column.
+TEST_F(TableViewTest, SortOnSpaceBar) {
+ if (!PlatformStyle::kTableViewSupportsKeyboardNavigationByCell)
+ return;
+
+ table_->RequestFocus();
+ ASSERT_TRUE(table_->sort_descriptors().empty());
+ // Table starts off with no visible column being active.
+ ASSERT_EQ(-1, helper_->GetActiveVisibleColumnIndex());
+
+ ui::ListSelectionModel new_selection;
+ new_selection.SetSelectedIndex(1);
+ helper_->SetSelectionModel(new_selection);
+ ASSERT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+
+ PressKey(ui::VKEY_SPACE);
+ ASSERT_EQ(1u, table_->sort_descriptors().size());
+ EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
+ EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
+
+ PressKey(ui::VKEY_SPACE);
+ ASSERT_EQ(1u, table_->sort_descriptors().size());
+ EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
+ EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
+
+ PressKey(ui::VKEY_RIGHT);
+ ASSERT_EQ(1, helper_->GetActiveVisibleColumnIndex());
+
+ PressKey(ui::VKEY_SPACE);
+ ASSERT_EQ(2u, table_->sort_descriptors().size());
+ EXPECT_EQ(1, table_->sort_descriptors()[0].column_id);
+ EXPECT_EQ(0, table_->sort_descriptors()[1].column_id);
+ EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
+ EXPECT_FALSE(table_->sort_descriptors()[1].ascending);
+}
+
namespace {
class TableGrouperImpl : public TableGrouper {
@@ -877,7 +1050,7 @@ TEST_F(TableViewTest, SelectOnTap) {
}
#endif
-// Verifies up/down correctly navigates through groups.
+// Verifies up/down correctly navigate through groups.
TEST_F(TableViewTest, KeyUpDown) {
// Configure the grouper so that there are three groups:
// A 0
@@ -1008,6 +1181,105 @@ TEST_F(TableViewTest, KeyUpDown) {
table_->set_observer(NULL);
}
+// Verifies left/right correctly navigate through visible columns.
+TEST_F(TableViewTest, KeyLeftRight) {
+ if (!PlatformStyle::kTableViewSupportsKeyboardNavigationByCell)
+ return;
+
+ TableViewObserverImpl observer;
+ table_->set_observer(&observer);
+ table_->RequestFocus();
+
+ // Initially no active visible column.
+ EXPECT_EQ(-1, helper_->GetActiveVisibleColumnIndex());
+
+ PressKey(ui::VKEY_RIGHT);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(1, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString());
+
+ helper_->SetSelectionModel(ui::ListSelectionModel());
+ EXPECT_EQ(-1, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(1, observer.GetChangedCountAndClear());
+
+ PressKey(ui::VKEY_LEFT);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(1, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString());
+
+ PressKey(ui::VKEY_RIGHT);
+ EXPECT_EQ(1, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString());
+
+ PressKey(ui::VKEY_RIGHT);
+ EXPECT_EQ(1, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString());
+
+ ui::ListSelectionModel new_selection;
+ new_selection.SetSelectedIndex(1);
+ helper_->SetSelectionModel(new_selection);
+ EXPECT_EQ(1, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(1, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ PressKey(ui::VKEY_LEFT);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ PressKey(ui::VKEY_LEFT);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ table_->SetColumnVisibility(0, false);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ // Since the first column was hidden, the active visible column should not
+ // advance.
+ PressKey(ui::VKEY_RIGHT);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ // If visibility to the first column is restored, the active visible column
+ // should be unchanged because columns are always added to the end.
+ table_->SetColumnVisibility(0, true);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+ PressKey(ui::VKEY_RIGHT);
+ EXPECT_EQ(1, helper_->GetActiveVisibleColumnIndex());
+
+ // If visibility to the first column is removed, the active visible column
+ // should be decreased by one.
+ table_->SetColumnVisibility(0, false);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ PressKey(ui::VKEY_LEFT);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ table_->SetColumnVisibility(0, true);
+ EXPECT_EQ(0, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ PressKey(ui::VKEY_RIGHT);
+ EXPECT_EQ(1, helper_->GetActiveVisibleColumnIndex());
+ EXPECT_EQ(0, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=1 anchor=1 selection=1", SelectionStateAsString());
+
+ table_->set_observer(NULL);
+}
+
// Verifies home/end do the right thing.
TEST_F(TableViewTest, HomeEnd) {
// Configure the grouper so that there are three groups:
@@ -1018,10 +1290,7 @@ TEST_F(TableViewTest, HomeEnd) {
// 3
model_->AddRow(2, 5, 0);
TableGrouperImpl grouper;
- std::vector<int> ranges;
- ranges.push_back(2);
- ranges.push_back(1);
- ranges.push_back(2);
+ std::vector<int> ranges{2, 1, 2};
grouper.SetRanges(ranges);
table_->SetGrouper(&grouper);
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index 2ff60335add..9bccf2bcc73 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -354,9 +354,9 @@ void Textfield::SetReadOnly(bool read_only) {
void Textfield::SetTextInputType(ui::TextInputType type) {
GetRenderText()->SetObscured(type == ui::TEXT_INPUT_TYPE_PASSWORD);
text_input_type_ = type;
- OnCaretBoundsChanged();
if (GetInputMethod())
GetInputMethod()->OnTextInputTypeChanged(this);
+ OnCaretBoundsChanged();
SchedulePaint();
}
@@ -914,7 +914,7 @@ bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
bool Textfield::GetDropFormats(
int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) {
+ std::set<ui::ClipboardFormatType>* format_types) {
if (!enabled() || read_only())
return false;
// TODO(msw): Can we support URL, FILENAME, etc.?
@@ -926,7 +926,7 @@ bool Textfield::GetDropFormats(
bool Textfield::CanDrop(const OSExchangeData& data) {
int formats;
- std::set<ui::Clipboard::FormatType> format_types;
+ std::set<ui::ClipboardFormatType> format_types;
GetDropFormats(&formats, &format_types);
return enabled() && !read_only() && data.HasAnyFormat(formats, format_types);
}
@@ -1046,7 +1046,7 @@ bool Textfield::HandleAccessibleAction(const ui::AXActionData& action_data) {
return false;
// TODO(nektar): Check that the focus_node_id matches the ID of this node.
const gfx::Range range(action_data.anchor_offset, action_data.focus_offset);
- return SetSelectionRange(range);
+ return SetEditableSelectionRange(range);
}
// Remaining actions cannot be performed on readonly fields.
@@ -1187,15 +1187,6 @@ void Textfield::OnCompositionTextConfirmedOrCleared() {
void Textfield::ShowContextMenuForView(View* source,
const gfx::Point& point,
ui::MenuSourceType source_type) {
-#if defined(OS_MACOSX)
- // On Mac, the context menu contains a look up item which displays the
- // selected text. As such, the menu needs to be updated if the selection has
- // changed. Be careful to reset the MenuRunner first so it doesn't reference
- // the old model.
- context_menu_runner_.reset();
- context_menu_contents_.reset();
-#endif
-
UpdateContextMenu();
context_menu_runner_->RunMenuAt(GetWidget(), NULL,
gfx::Rect(point, gfx::Size()),
@@ -1590,14 +1581,14 @@ bool Textfield::GetCompositionTextRange(gfx::Range* range) const {
return true;
}
-bool Textfield::GetSelectionRange(gfx::Range* range) const {
+bool Textfield::GetEditableSelectionRange(gfx::Range* range) const {
if (!ImeEditingAllowed())
return false;
*range = GetRenderText()->selection();
return true;
}
-bool Textfield::SetSelectionRange(const gfx::Range& range) {
+bool Textfield::SetEditableSelectionRange(const gfx::Range& range) {
if (!ImeEditingAllowed() || !range.IsValid())
return false;
OnBeforeUserAction();
@@ -2265,30 +2256,33 @@ bool Textfield::Paste() {
}
void Textfield::UpdateContextMenu() {
- if (!context_menu_contents_.get()) {
- context_menu_contents_.reset(new ui::SimpleMenuModel(this));
- context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
- context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
- context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
- context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
- context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
- context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
- context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
- context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
- IDS_APP_SELECT_ALL);
-
- // If the controller adds menu commands, also override ExecuteCommand() and
- // IsCommandIdEnabled() as appropriate, for the commands added.
- if (controller_)
- controller_->UpdateContextMenu(context_menu_contents_.get());
+ // TextfieldController may modify Textfield's menu, so the menu should be
+ // recreated each time it's shown. Reset the MenuRunner first so it doesn't
+ // reference the old menu model.
+ context_menu_runner_.reset();
- text_services_context_menu_ = ViewsTextServicesContextMenu::Create(
- context_menu_contents_.get(), this);
- }
+ context_menu_contents_.reset(new ui::SimpleMenuModel(this));
+ context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
+ context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
+ context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
+ IDS_APP_SELECT_ALL);
+
+ // If the controller adds menu commands, also override ExecuteCommand() and
+ // IsCommandIdEnabled() as appropriate, for the commands added.
+ if (controller_)
+ controller_->UpdateContextMenu(context_menu_contents_.get());
+
+ text_services_context_menu_ =
+ ViewsTextServicesContextMenu::Create(context_menu_contents_.get(), this);
- context_menu_runner_.reset(
- new MenuRunner(context_menu_contents_.get(),
- MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU));
+ context_menu_runner_ = std::make_unique<MenuRunner>(
+ context_menu_contents_.get(),
+ MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU);
}
bool Textfield::ImeEditingAllowed() const {
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index f5d0914d43e..db72373b795 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -264,9 +264,8 @@ class VIEWS_EXPORT Textfield : public View,
bool CanHandleAccelerators() const override;
void AboutToRequestFocusFromTabTraversal(bool reverse) override;
bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override;
- bool GetDropFormats(
- int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) override;
+ bool GetDropFormats(int* formats,
+ std::set<ui::ClipboardFormatType>* format_types) override;
bool CanDrop(const ui::OSExchangeData& data) override;
int OnDragUpdated(const ui::DropTargetEvent& event) override;
void OnDragExited() override;
@@ -349,8 +348,8 @@ class VIEWS_EXPORT Textfield : public View,
FocusReason GetFocusReason() const override;
bool GetTextRange(gfx::Range* range) const override;
bool GetCompositionTextRange(gfx::Range* range) const override;
- bool GetSelectionRange(gfx::Range* range) const override;
- bool SetSelectionRange(const gfx::Range& range) override;
+ bool GetEditableSelectionRange(gfx::Range* range) const override;
+ bool SetEditableSelectionRange(const gfx::Range& range) override;
bool DeleteRange(const gfx::Range& range) override;
bool GetTextFromRange(const gfx::Range& range,
base::string16* text) const override;
diff --git a/chromium/ui/views/controls/textfield/textfield_controller.h b/chromium/ui/views/controls/textfield/textfield_controller.h
index 041abebadeb..f5ecb1da07c 100644
--- a/chromium/ui/views/controls/textfield/textfield_controller.h
+++ b/chromium/ui/views/controls/textfield/textfield_controller.h
@@ -8,6 +8,8 @@
#include <set>
#include "base/strings/string16.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/clipboard/clipboard_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/views/views_export.h"
@@ -76,7 +78,7 @@ class VIEWS_EXPORT TextfieldController {
// Enables the controller to append to the accepted drop formats.
virtual void AppendDropFormats(
int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) {}
+ std::set<ui::ClipboardFormatType>* format_types) {}
// Called when a drop of dragged data happens on the textfield. This method is
// called before regular handling of the drop. If this returns a drag
diff --git a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
index 60884ff58b0..75d45261625 100644
--- a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/auto_reset.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -1881,9 +1881,9 @@ TEST_F(TextfieldModelTest, Transpose) {
TextfieldModel model(nullptr);
- EXPECT_EQ(all_tests.size(), arraysize(test_strings));
+ EXPECT_EQ(all_tests.size(), base::size(test_strings));
- for (size_t i = 0; i < arraysize(test_strings); i++) {
+ for (size_t i = 0; i < base::size(test_strings); i++) {
for (size_t j = 0; j < all_tests[i].size(); j++) {
SCOPED_TRACE(testing::Message() << "Testing case " << i << ", " << j
<< " with string " << test_strings[i]);
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index 879ebf11a83..7ae476515d8 100644
--- a/chromium/ui/views/controls/textfield/textfield_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -15,12 +15,11 @@
#include "base/command_line.h"
#include "base/format_macros.h"
#include "base/i18n/rtl.h"
-#include "base/macros.h"
#include "base/pickle.h"
+#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/aura/window.h"
@@ -35,7 +34,6 @@
#include "ui/base/ime/text_edit_commands.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/events/event.h"
@@ -720,6 +718,14 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
textfield_->GetSelectedRange().length() == text.length();
int menu_index = 0;
+
+#if defined(OS_MACOSX)
+ if (textfield_has_selection) {
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Look Up "Selection" */));
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
+ }
+#endif
+
if (ui::IsEmojiPanelSupported()) {
EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* EMOJI */));
EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
@@ -970,7 +976,7 @@ TEST_F(TextfieldTest, WordSelection) {
textfield_->SetText(ASCIIToUTF16("12 34567 89"));
// Place the cursor after "5".
- textfield_->SetSelectionRange(gfx::Range(6));
+ textfield_->SetEditableSelectionRange(gfx::Range(6));
// Select word towards right.
SendWordEvent(ui::VKEY_RIGHT, true);
@@ -1013,7 +1019,7 @@ TEST_F(TextfieldTest, LineSelection) {
textfield_->SetText(ASCIIToUTF16("12 34567 89"));
// Place the cursor after "5".
- textfield_->SetSelectionRange(gfx::Range(6));
+ textfield_->SetEditableSelectionRange(gfx::Range(6));
// Select line towards right.
SendEndEvent(true);
@@ -1042,7 +1048,7 @@ TEST_F(TextfieldTest, LineSelection) {
TEST_F(TextfieldTest, MoveUpDownAndModifySelection) {
InitTextfield();
textfield_->SetText(ASCIIToUTF16("12 34567 89"));
- textfield_->SetSelectionRange(gfx::Range(6));
+ textfield_->SetEditableSelectionRange(gfx::Range(6));
// Up/Down keys won't be handled except on Mac where they map to move
// commands.
@@ -1066,7 +1072,7 @@ TEST_F(TextfieldTest, MoveUpDownAndModifySelection) {
#endif
textfield_->clear();
- textfield_->SetSelectionRange(gfx::Range(6));
+ textfield_->SetEditableSelectionRange(gfx::Range(6));
// Shift+[Up/Down] should select the text to the beginning and end of the
// line, respectively.
@@ -1090,7 +1096,7 @@ TEST_F(TextfieldTest, MovePageUpDownAndModifySelection) {
// enabled on Mac.
#if defined(OS_MACOSX)
textfield_->SetText(ASCIIToUTF16("12 34567 89"));
- textfield_->SetSelectionRange(gfx::Range(6));
+ textfield_->SetEditableSelectionRange(gfx::Range(6));
EXPECT_TRUE(
textfield_->IsTextEditCommandEnabled(ui::TextEditCommand::MOVE_PAGE_UP));
@@ -1107,7 +1113,7 @@ TEST_F(TextfieldTest, MovePageUpDownAndModifySelection) {
test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_PAGE_DOWN);
EXPECT_EQ(gfx::Range(11), textfield_->GetSelectedRange());
- textfield_->SetSelectionRange(gfx::Range(6));
+ textfield_->SetEditableSelectionRange(gfx::Range(6));
test_api_->ExecuteTextEditCommand(
ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION);
EXPECT_EQ(gfx::Range(6, 0), textfield_->GetSelectedRange());
@@ -1130,7 +1136,7 @@ TEST_F(TextfieldTest, MovePageUpDownAndModifySelection) {
TEST_F(TextfieldTest, MoveParagraphForwardBackwardAndModifySelection) {
InitTextfield();
textfield_->SetText(ASCIIToUTF16("12 34567 89"));
- textfield_->SetSelectionRange(gfx::Range(6));
+ textfield_->SetEditableSelectionRange(gfx::Range(6));
test_api_->ExecuteTextEditCommand(
ui::TextEditCommand::MOVE_PARAGRAPH_FORWARD_AND_MODIFY_SELECTION);
@@ -1237,7 +1243,7 @@ TEST_F(TextfieldTest, DeletionWithSelection) {
InitTextfield();
// [Ctrl] ([Alt] on Mac) + [Delete]/[Backspace] should delete the active
// selection, regardless of [Shift].
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
textfield_->SetText(ASCIIToUTF16("one two three"));
textfield_->SelectRange(gfx::Range(2, 6));
@@ -1555,8 +1561,6 @@ TEST_F(TextfieldTest, FocusTraversalTest) {
TEST_F(TextfieldTest, ContextMenuDisplayTest) {
InitTextfield();
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(features::kEnableEmojiContextMenu);
EXPECT_TRUE(textfield_->context_menu_controller());
textfield_->SetText(ASCIIToUTF16("hello world"));
@@ -1705,7 +1709,7 @@ TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) {
base::string16 string(ASCIIToUTF16("string "));
data.SetString(string);
int formats = 0;
- std::set<ui::Clipboard::FormatType> format_types;
+ std::set<ui::ClipboardFormatType> format_types;
// Ensure that disabled textfields do not accept drops.
textfield_->SetEnabled(false);
@@ -1739,7 +1743,7 @@ TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) {
// Ensure that textfields do not accept non-OSExchangeData::STRING types.
ui::OSExchangeData bad_data;
bad_data.SetFilename(base::FilePath(FILE_PATH_LITERAL("x")));
- ui::Clipboard::FormatType fmt = ui::Clipboard::GetBitmapFormatType();
+ ui::ClipboardFormatType fmt = ui::ClipboardFormatType::GetBitmapType();
bad_data.SetPickledData(fmt, base::Pickle());
bad_data.SetFileContents(base::FilePath(L"x"), "x");
bad_data.SetHtml(base::string16(ASCIIToUTF16("x")), GURL("x.org"));
@@ -1803,7 +1807,7 @@ TEST_F(TextfieldTest, DragAndDrop_ToTheRight) {
ui::OSExchangeData data;
int formats = 0;
int operations = 0;
- std::set<ui::Clipboard::FormatType> format_types;
+ std::set<ui::ClipboardFormatType> format_types;
// Start dragging "ello".
textfield_->SelectRange(gfx::Range(1, 5));
@@ -1854,7 +1858,7 @@ TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) {
ui::OSExchangeData data;
int formats = 0;
int operations = 0;
- std::set<ui::Clipboard::FormatType> format_types;
+ std::set<ui::ClipboardFormatType> format_types;
// Start dragging " worl".
textfield_->SelectRange(gfx::Range(5, 10));
@@ -2001,8 +2005,8 @@ TEST_F(TextfieldTest, TextInputClientTest) {
EXPECT_EQ(0U, range.start());
EXPECT_EQ(10U, range.end());
- EXPECT_TRUE(client->SetSelectionRange(gfx::Range(1, 4)));
- EXPECT_TRUE(client->GetSelectionRange(&range));
+ EXPECT_TRUE(client->SetEditableSelectionRange(gfx::Range(1, 4)));
+ EXPECT_TRUE(client->GetEditableSelectionRange(&range));
EXPECT_EQ(gfx::Range(1, 4), range);
base::string16 substring;
@@ -2064,7 +2068,7 @@ TEST_F(TextfieldTest, TextInputClientTest) {
textfield_->clear();
textfield_->SetText(ASCIIToUTF16("0123456789"));
- EXPECT_TRUE(client->SetSelectionRange(gfx::Range(5, 5)));
+ EXPECT_TRUE(client->SetEditableSelectionRange(gfx::Range(5, 5)));
client->ExtendSelectionAndDelete(4, 2);
EXPECT_STR_EQ("0789", textfield_->text());
@@ -2777,7 +2781,7 @@ TEST_F(TextfieldTest, GetCompositionCharacterBounds_ComplexText) {
// U+0020 SPACE
0x0020,
};
- const size_t kUtf16CharsCount = arraysize(kUtf16Chars);
+ const size_t kUtf16CharsCount = base::size(kUtf16Chars);
ui::CompositionText composition;
composition.text.assign(kUtf16Chars, kUtf16Chars + kUtf16CharsCount);
@@ -3227,23 +3231,23 @@ TEST_F(TextfieldTouchSelectionTest, MAYBE_TapOnSelection) {
// Select range |sel_range| and check if touch selection handles are not
// present and correct range is selected.
- textfield_->SetSelectionRange(sel_range);
+ textfield_->SetEditableSelectionRange(sel_range);
gfx::Range range;
- textfield_->GetSelectionRange(&range);
+ textfield_->GetEditableSelectionRange(&range);
EXPECT_FALSE(test_api_->touch_selection_controller());
EXPECT_EQ(sel_range, range);
// Tap on selection and check if touch selectoin handles are shown, but
// selection range is not modified.
Tap(tap_point);
- textfield_->GetSelectionRange(&range);
+ textfield_->GetEditableSelectionRange(&range);
EXPECT_TRUE(test_api_->touch_selection_controller());
EXPECT_EQ(sel_range, range);
// Tap again on selection and check if touch selection handles are still
// present and selection is changed to a cursor at tap location.
Tap(tap_point);
- textfield_->GetSelectionRange(&range);
+ textfield_->GetEditableSelectionRange(&range);
EXPECT_TRUE(test_api_->touch_selection_controller());
EXPECT_EQ(tap_range, range);
}
@@ -3444,10 +3448,6 @@ TEST_F(TextfieldTest, EmojiItem_EmptyField) {
InitTextfield();
EXPECT_TRUE(textfield_->context_menu_controller());
- // Enable the emoji feature.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(features::kEnableEmojiContextMenu);
-
// A normal empty field may show the Emoji option (if supported).
ui::MenuModel* context_menu = GetContextMenuModel();
EXPECT_TRUE(context_menu);
@@ -3462,10 +3462,6 @@ TEST_F(TextfieldTest, EmojiItem_ReadonlyField) {
InitTextfield();
EXPECT_TRUE(textfield_->context_menu_controller());
- // Enable the emoji feature.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(features::kEnableEmojiContextMenu);
-
textfield_->SetReadOnly(true);
// In no case is the emoji option showing on a read-only field.
ui::MenuModel* context_menu = GetContextMenuModel();
@@ -3487,10 +3483,6 @@ TEST_F(TextfieldTest, EmojiItem_FieldWithText) {
constexpr int kExpectedEmojiIndex = 0;
#endif
- // Enable the emoji feature.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(features::kEnableEmojiContextMenu);
-
// A field with text may still show the Emoji option (if supported).
textfield_->SetText(base::ASCIIToUTF16("some text"));
textfield_->SelectAll(false);
@@ -3541,10 +3533,6 @@ TEST_F(TextfieldTest, LookUpItemUpdate) {
InitTextfield();
EXPECT_TRUE(textfield_->context_menu_controller());
- // Make sure the Emoji feature is disabled for this test.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(features::kEnableEmojiContextMenu);
-
const base::string16 kTextOne = ASCIIToUTF16("crake");
textfield_->SetText(kTextOne);
textfield_->SelectAll(false);
diff --git a/chromium/ui/views/controls/views_text_services_context_menu_base.cc b/chromium/ui/views/controls/views_text_services_context_menu_base.cc
index 89858fbb099..33950f58172 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu_base.cc
+++ b/chromium/ui/views/controls/views_text_services_context_menu_base.cc
@@ -14,16 +14,14 @@
#include "ui/resources/grit/ui_resources.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/widget/widget.h"
namespace views {
namespace {
-const char kViewsTextServicesContextMenuHistogram[] =
- "ViewsTextServicesContextMenu.Used";
-
-// Do not change the values in this enum as they are used by UMA.
-enum class Command { kEmoji = 0, kMaxValue = kEmoji };
+const char kViewsTextServicesContextMenuEmoji[] =
+ "ContextMenu.ViewsTextServices.Emoji";
} // namespace
@@ -82,9 +80,8 @@ bool ViewsTextServicesContextMenuBase::IsCommandIdEnabled(
void ViewsTextServicesContextMenuBase::ExecuteCommand(int command_id) {
if (command_id == IDS_CONTENT_CONTEXT_EMOJI) {
- ui::ShowEmojiPanel();
- UMA_HISTOGRAM_ENUMERATION(kViewsTextServicesContextMenuHistogram,
- Command::kEmoji);
+ client()->GetWidget()->ShowEmojiPanel();
+ UMA_HISTOGRAM_BOOLEAN(kViewsTextServicesContextMenuEmoji, true);
}
}
diff --git a/chromium/ui/views/controls/webview/web_contents_set_background_color.cc b/chromium/ui/views/controls/webview/web_contents_set_background_color.cc
index cfdf3e6b6b1..d704fad318d 100644
--- a/chromium/ui/views/controls/webview/web_contents_set_background_color.cc
+++ b/chromium/ui/views/controls/webview/web_contents_set_background_color.cc
@@ -52,4 +52,6 @@ void WebContentsSetBackgroundColor::RenderViewHostChanged(
new_host->GetWidget()->GetView()->SetBackgroundColor(color_);
}
+WEB_CONTENTS_USER_DATA_KEY_IMPL(WebContentsSetBackgroundColor)
+
} // namespace views
diff --git a/chromium/ui/views/controls/webview/web_contents_set_background_color.h b/chromium/ui/views/controls/webview/web_contents_set_background_color.h
index e10a3a3bf06..9bac23b4e8a 100644
--- a/chromium/ui/views/controls/webview/web_contents_set_background_color.h
+++ b/chromium/ui/views/controls/webview/web_contents_set_background_color.h
@@ -27,6 +27,7 @@ class WebContentsSetBackgroundColor
~WebContentsSetBackgroundColor() override;
private:
+ friend class content::WebContentsUserData<WebContentsSetBackgroundColor>;
WebContentsSetBackgroundColor(content::WebContents* web_contents,
SkColor color);
@@ -38,6 +39,8 @@ class WebContentsSetBackgroundColor
SkColor color_;
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+
DISALLOW_COPY_AND_ASSIGN(WebContentsSetBackgroundColor);
};
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.cc b/chromium/ui/views/controls/webview/web_dialog_view.cc
index e2023e4030f..dcf1cd296ea 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view.cc
@@ -292,8 +292,8 @@ bool WebDialogView::HandleKeyboardEvent(content::WebContents* source,
if (!event.os_event)
return false;
- GetWidget()->native_widget_private()->RepostNativeEvent(event.os_event);
- return true;
+ return unhandled_keyboard_event_handler_.HandleKeyboardEvent(
+ event, GetFocusManager());
}
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 6467993163f..27e9742ecac 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.h
+++ b/chromium/ui/views/controls/webview/web_dialog_view.h
@@ -14,6 +14,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/controls/webview/webview_export.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
@@ -161,6 +162,9 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// Whether CloseContents() has been called.
bool close_contents_called_ = false;
+ // Handler for unhandled key events from renderer.
+ UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
+
DISALLOW_COPY_AND_ASSIGN(WebDialogView);
};
diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc
index 15e497fcf41..00376535df5 100644
--- a/chromium/ui/views/controls/webview/webview.cc
+++ b/chromium/ui/views/controls/webview/webview.cc
@@ -11,6 +11,7 @@
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
@@ -253,7 +254,7 @@ void WebView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->SetNameExplicitlyEmpty();
if (child_ax_tree_id_ != ui::AXTreeIDUnknown()) {
node_data->AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
- child_ax_tree_id_);
+ child_ax_tree_id_.ToString());
}
}
@@ -365,6 +366,10 @@ void WebView::AttachWebContents() {
holder_->Attach(view_to_attach);
+ // We set the parent accessible of the native view to be our parent.
+ if (parent())
+ holder_->SetParentAccessible(parent()->GetNativeViewAccessible());
+
// The WebContents is not focused automatically when attached, so we need to
// tell the WebContents it has focus if this has focus.
if (HasFocus())
@@ -374,8 +379,9 @@ void WebView::AttachWebContents() {
}
void WebView::DetachWebContents() {
- if (web_contents())
+ if (web_contents()) {
holder_->Detach();
+ }
}
void WebView::ReattachForFullscreenChange(bool enter_fullscreen) {
@@ -414,10 +420,7 @@ void WebView::UpdateCrashedOverlayView() {
void WebView::NotifyAccessibilityWebContentsChanged() {
content::RenderFrameHost* rfh =
web_contents() ? web_contents()->GetMainFrame() : nullptr;
- if (rfh)
- child_ax_tree_id_ = rfh->GetAXTreeID();
- else
- child_ax_tree_id_ = ui::AXTreeIDUnknown();
+ child_ax_tree_id_ = rfh ? rfh->GetAXTreeID() : ui::AXTreeIDUnknown();
NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false);
}
diff --git a/chromium/ui/views/controls/webview/webview_unittest.cc b/chromium/ui/views/controls/webview/webview_unittest.cc
index 27be01b37a9..6f69e632812 100644
--- a/chromium/ui/views/controls/webview/webview_unittest.cc
+++ b/chromium/ui/views/controls/webview/webview_unittest.cc
@@ -126,8 +126,7 @@ class WebViewTestWebContentsDelegate : public content::WebContentsDelegate {
class WebViewUnitTest : public views::test::WidgetTest {
public:
WebViewUnitTest() = default;
-
- ~WebViewUnitTest() override {}
+ ~WebViewUnitTest() override = default;
std::unique_ptr<content::WebContents> CreateWebContentsForWebView(
content::BrowserContext* browser_context) {
@@ -136,6 +135,10 @@ class WebViewUnitTest : public views::test::WidgetTest {
}
void SetUp() override {
+ set_scoped_task_environment(
+ std::make_unique<content::TestBrowserThreadBundle>());
+ rvh_enabler_ = std::make_unique<content::RenderViewHostTestEnabler>();
+
views::WebView::WebContentsCreator creator = base::BindRepeating(
&WebViewUnitTest::CreateWebContentsForWebView, base::Unretained(this));
scoped_web_contents_creator_ =
@@ -187,8 +190,7 @@ class WebViewUnitTest : public views::test::WidgetTest {
}
private:
- content::TestBrowserThreadBundle test_browser_thread_bundle_;
- content::RenderViewHostTestEnabler rvh_enabler_;
+ std::unique_ptr<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/DEPS b/chromium/ui/views/corewm/DEPS
index 150fabd64ff..f3f534060bc 100644
--- a/chromium/ui/views/corewm/DEPS
+++ b/chromium/ui/views/corewm/DEPS
@@ -21,6 +21,7 @@ specific_include_rules = {
],
"desktop_capture_controller_unittest.cc": [
+ "+ui/views/test/native_widget_factory.h",
"+ui/views/test/views_interactive_ui_test_base.h",
"+ui/views/view.h",
"+ui/views/widget/desktop_aura/desktop_native_widget_aura.h",
diff --git a/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc b/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
index b4b852f9f2e..b1b8e8263b3 100644
--- a/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
+++ b/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
@@ -12,6 +12,7 @@
#include "ui/aura/window_tree_host.h"
#include "ui/events/event.h"
#include "ui/events/test/event_generator.h"
+#include "ui/views/test/native_widget_factory.h"
#include "ui/views/test/views_interactive_ui_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@@ -103,6 +104,8 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
aura::client::CaptureClient* capture_client = wm::CaptureController::Get();
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(50, 50, 650, 650);
+ params.native_widget = test::CreatePlatformNativeWidgetImpl(
+ params, widget1.get(), test::kStubCapture, nullptr);
widget1->Init(params);
internal::RootView* root1 =
static_cast<internal::RootView*>(widget1->GetRootView());
@@ -123,6 +126,8 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(50, 50, 650, 650);
+ params.native_widget = test::CreatePlatformNativeWidgetImpl(
+ params, widget2.get(), test::kStubCapture, nullptr);
widget2->Init(params);
internal::RootView* root2 =
diff --git a/chromium/ui/views/corewm/tooltip_controller_unittest.cc b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
index 77372afa1b6..94f6648088c 100644
--- a/chromium/ui/views/corewm/tooltip_controller_unittest.cc
+++ b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/views/corewm/tooltip_controller.h"
+#include "base/at_exit.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -60,9 +61,6 @@ views::Widget* CreateWidget(aura::Window* root) {
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
#if defined(OS_CHROMEOS)
params.parent = root;
-#else
- params.native_widget = ::views::test::CreatePlatformDesktopNativeWidgetImpl(
- params, widget, nullptr);
#endif
params.bounds = gfx::Rect(0, 0, 200, 100);
widget->Init(params);
@@ -79,10 +77,14 @@ TooltipController* GetController(Widget* widget) {
class TooltipControllerTest : public ViewsTestBase {
public:
- TooltipControllerTest() : view_(NULL) {}
+ TooltipControllerTest() = default;
~TooltipControllerTest() override {}
void SetUp() override {
+#if !defined(OS_CHROMEOS)
+ set_native_widget_type(NativeWidgetType::kDesktop);
+#endif
+
ViewsTestBase::SetUp();
aura::Window* root_window = GetContext();
@@ -156,7 +158,7 @@ class TooltipControllerTest : public ViewsTestBase {
}
std::unique_ptr<views::Widget> widget_;
- TooltipTestView* view_;
+ TooltipTestView* view_ = nullptr;
std::unique_ptr<TooltipControllerTestHelper> helper_;
std::unique_ptr<ui::test::EventGenerator> generator_;
@@ -236,11 +238,6 @@ TEST_F(TooltipControllerTest, DontShowTooltipOnTouch) {
#if defined(OS_CHROMEOS)
// crbug.com/664370.
TEST_F(TooltipControllerTest, MaxWidth) {
- // This test relies on TooltipAura being created, which does not happen in
- // this test with mus (it happens in DesktopNativeWidgetAura).
- if (IsMus())
- return;
-
base::string16 text = base::ASCIIToUTF16(
"Really really realy long long long long long tooltips that exceeds max "
"width");
@@ -482,8 +479,7 @@ class TooltipControllerCaptureTest : public TooltipControllerTest {
}
void TearDown() override {
- if (!IsMus())
- aura::client::SetScreenPositionClient(GetRootWindow(), NULL);
+ aura::client::SetScreenPositionClient(GetRootWindow(), NULL);
TooltipControllerTest::TearDown();
}
@@ -522,11 +518,6 @@ TEST_F(TooltipControllerCaptureTest, DISABLED_CloseOnCaptureLost) {
#endif
// Verifies the correct window is found for tooltips when there is a capture.
TEST_F(TooltipControllerCaptureTest, MAYBE_Capture) {
- // This test doesn't make sense with mus as it creates two widgets and
- // expects to move the mouse between them.
- if (IsMus())
- return;
-
const base::string16 tooltip_text(ASCIIToUTF16("1"));
const base::string16 tooltip_text2(ASCIIToUTF16("2"));
@@ -610,6 +601,7 @@ class TooltipControllerTest2 : public aura::test::AuraTestBase {
~TooltipControllerTest2() override {}
void SetUp() override {
+ at_exit_manager_ = std::make_unique<base::ShadowingAtExitManager>();
aura::test::AuraTestBase::SetUp();
new wm::DefaultActivationClient(root_window());
controller_.reset(
@@ -627,6 +619,7 @@ class TooltipControllerTest2 : public aura::test::AuraTestBase {
generator_.reset();
helper_.reset();
aura::test::AuraTestBase::TearDown();
+ at_exit_manager_.reset();
}
protected:
@@ -636,17 +629,14 @@ class TooltipControllerTest2 : public aura::test::AuraTestBase {
std::unique_ptr<ui::test::EventGenerator> generator_;
private:
+ // Needed to make sure the InputDeviceManager is cleaned up between test runs.
+ std::unique_ptr<base::ShadowingAtExitManager> at_exit_manager_;
std::unique_ptr<TooltipController> controller_;
DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest2);
};
TEST_F(TooltipControllerTest2, VerifyLeadingTrailingWhitespaceStripped) {
- // This test does not have a real connection to mus (because it's using
- // AuraTestBase, not ViewsTestBase), so it can't use EventGenerator.
- if (ViewsTestBase::IsMus())
- return;
-
aura::test::TestWindowDelegate test_delegate;
std::unique_ptr<aura::Window> window(
CreateNormalWindow(100, root_window(), &test_delegate));
@@ -660,11 +650,6 @@ TEST_F(TooltipControllerTest2, VerifyLeadingTrailingWhitespaceStripped) {
// Verifies that tooltip is hidden and tooltip window closed upon cancel mode.
TEST_F(TooltipControllerTest2, CloseOnCancelMode) {
- // This test does not have a real connection to mus (because it's using
- // AuraTestBase, not ViewsTestBase), so it can't use EventGenerator.
- if (ViewsTestBase::IsMus())
- return;
-
aura::test::TestWindowDelegate test_delegate;
std::unique_ptr<aura::Window> window(
CreateNormalWindow(100, root_window(), &test_delegate));
@@ -691,12 +676,11 @@ class TooltipControllerTest3 : public ViewsTestBase {
~TooltipControllerTest3() override = default;
void SetUp() override {
- ViewsTestBase::SetUp();
+#if !defined(OS_CHROMEOS)
+ set_native_widget_type(NativeWidgetType::kDesktop);
+#endif
- // This test assumes a hierarchy like that of Ash, which doesn't make sense
- // with mus.
- if (IsMus())
- return;
+ ViewsTestBase::SetUp();
aura::Window* root_window = GetContext();
new wm::DefaultActivationClient(root_window);
@@ -721,15 +705,13 @@ class TooltipControllerTest3 : public ViewsTestBase {
}
void TearDown() override {
- if (!IsMus()) {
- GetRootWindow()->RemovePreTargetHandler(controller_.get());
- wm::SetTooltipClient(GetRootWindow(), NULL);
+ GetRootWindow()->RemovePreTargetHandler(controller_.get());
+ wm::SetTooltipClient(GetRootWindow(), NULL);
- controller_.reset();
- generator_.reset();
- helper_.reset();
- widget_.reset();
- }
+ controller_.reset();
+ generator_.reset();
+ helper_.reset();
+ widget_.reset();
ViewsTestBase::TearDown();
}
@@ -756,11 +738,6 @@ class TooltipControllerTest3 : public ViewsTestBase {
};
TEST_F(TooltipControllerTest3, TooltipPositionChangesOnTwoViewsWithSameLabel) {
- // See comment in TooltipControllerTest3::SetUp() for why this does nothing in
- // mus.
- if (IsMus())
- return;
-
// Owned by |view_|.
// These two views have the same tooltip text
TooltipTestView* v1 = new TooltipTestView;
diff --git a/chromium/ui/views/corewm/tooltip_win.cc b/chromium/ui/views/corewm/tooltip_win.cc
index 918be16ed81..3acf4bae306 100644
--- a/chromium/ui/views/corewm/tooltip_win.cc
+++ b/chromium/ui/views/corewm/tooltip_win.cc
@@ -159,6 +159,10 @@ void TooltipWin::Show() {
SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE,
TRUE, reinterpret_cast<LPARAM>(&toolinfo_));
+
+ // Bring the window to the front.
+ SetWindowPos(tooltip_hwnd_, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE);
}
void TooltipWin::Hide() {
diff --git a/chromium/ui/views/event_monitor_unittest.cc b/chromium/ui/views/event_monitor_unittest.cc
index 6db69c176c5..fdda4562448 100644
--- a/chromium/ui/views/event_monitor_unittest.cc
+++ b/chromium/ui/views/event_monitor_unittest.cc
@@ -44,18 +44,8 @@ class EventMonitorTest : public WidgetTest {
widget_ = CreateTopLevelNativeWidget();
widget_->SetSize(gfx::Size(100, 100));
widget_->Show();
- if (IsMus()) {
- 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_ = std::make_unique<ui::test::EventGenerator>(
- GetContext(), widget_->GetNativeWindow());
- }
+ generator_ = std::make_unique<ui::test::EventGenerator>(
+ GetContext(), widget_->GetNativeWindow());
generator_->set_target(ui::test::EventGenerator::Target::APPLICATION);
}
void TearDown() override {
diff --git a/chromium/ui/views/examples/BUILD.gn b/chromium/ui/views/examples/BUILD.gn
index eab97ae3045..f665273a843 100644
--- a/chromium/ui/views/examples/BUILD.gn
+++ b/chromium/ui/views/examples/BUILD.gn
@@ -31,6 +31,8 @@ jumbo_component("views_examples_lib") {
"example_combobox_model.h",
"examples_window.cc",
"examples_window.h",
+ "flex_layout_example.cc",
+ "flex_layout_example.h",
"label_example.cc",
"label_example.h",
"layout_example_base.cc",
diff --git a/chromium/ui/views/examples/OWNERS b/chromium/ui/views/examples/OWNERS
new file mode 100644
index 00000000000..add7cbf5403
--- /dev/null
+++ b/chromium/ui/views/examples/OWNERS
@@ -0,0 +1 @@
+per-file *layout*=dfried@chromium.org \ No newline at end of file
diff --git a/chromium/ui/views/examples/bubble_example.cc b/chromium/ui/views/examples/bubble_example.cc
index a93f6c402a5..07127e68caa 100644
--- a/chromium/ui/views/examples/bubble_example.cc
+++ b/chromium/ui/views/examples/bubble_example.cc
@@ -4,7 +4,7 @@
#include "ui/views/examples/bubble_example.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
@@ -95,7 +95,7 @@ void BubbleExample::CreateExampleView(View* container) {
void BubbleExample::ButtonPressed(Button* sender, const ui::Event& event) {
static int arrow_index = 0, color_index = 0;
- static const int count = arraysize(arrows);
+ static const int count = base::size(arrows);
arrow_index = (arrow_index + count + (event.IsShiftDown() ? -1 : 1)) % count;
BubbleBorder::Arrow arrow = arrows[arrow_index];
if (event.IsControlDown())
@@ -104,7 +104,7 @@ void BubbleExample::ButtonPressed(Button* sender, const ui::Event& event) {
arrow = BubbleBorder::FLOAT;
ExampleBubble* bubble = new ExampleBubble(sender, arrow);
- bubble->set_color(colors[(color_index++) % arraysize(colors)]);
+ bubble->set_color(colors[(color_index++) % base::size(colors)]);
if (sender == no_shadow_)
bubble->set_shadow(BubbleBorder::NO_SHADOW);
diff --git a/chromium/ui/views/examples/examples_main.cc b/chromium/ui/views/examples/examples_main.cc
index f2f3a2a205b..5eda9d51221 100644
--- a/chromium/ui/views/examples/examples_main.cc
+++ b/chromium/ui/views/examples/examples_main.cc
@@ -15,6 +15,7 @@
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/test_discardable_memory_allocator.h"
+#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
@@ -68,6 +69,10 @@ int main(int argc, char** argv) {
gl::init::InitializeGLOneOff();
+ // The use of base::test::ScopedTaskEnvironment below relies on the timeout
+ // values from TestTimeouts. This ensures they're properly initialized.
+ TestTimeouts::Initialize();
+
// The ContextFactory must exist before any Compositors are created.
viz::HostFrameSinkManager host_frame_sink_manager;
viz::ServerSharedBitmapManager shared_bitmap_manager;
diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc
index 0c3689af6c7..5f76b6cebef 100644
--- a/chromium/ui/views/examples/examples_window.cc
+++ b/chromium/ui/views/examples/examples_window.cc
@@ -27,6 +27,7 @@
#include "ui/views/examples/checkbox_example.h"
#include "ui/views/examples/combobox_example.h"
#include "ui/views/examples/dialog_example.h"
+#include "ui/views/examples/flex_layout_example.h"
#include "ui/views/examples/label_example.h"
#include "ui/views/examples/link_example.h"
#include "ui/views/examples/menu_example.h"
@@ -68,6 +69,7 @@ ExampleVector CreateExamples() {
examples.push_back(std::make_unique<CheckboxExample>());
examples.push_back(std::make_unique<ComboboxExample>());
examples.push_back(std::make_unique<DialogExample>());
+ examples.push_back(std::make_unique<FlexLayoutExample>());
examples.push_back(std::make_unique<LabelExample>());
examples.push_back(std::make_unique<LinkExample>());
examples.push_back(std::make_unique<MenuExample>());
diff --git a/chromium/ui/views/examples/flex_layout_example.cc b/chromium/ui/views/examples/flex_layout_example.cc
new file mode 100644
index 00000000000..eddf3c29ebc
--- /dev/null
+++ b/chromium/ui/views/examples/flex_layout_example.cc
@@ -0,0 +1,118 @@
+// 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/flex_layout_example.h"
+
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/models/combobox_model.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.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/label.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.h"
+
+namespace views {
+namespace examples {
+
+FlexLayoutExample::FlexLayoutExample() : LayoutExampleBase("Flex Layout") {}
+
+FlexLayoutExample::~FlexLayoutExample() {}
+
+void FlexLayoutExample::CreateAdditionalControls(int vertical_pos) {
+ static const char* const orientation_values[2] = {"Horizontal", "Vertical"};
+ static const char* const main_axis_values[3] = {"Start", "Center", "End"};
+ static const char* const cross_axis_values[4] = {"Stretch", "Start", "Center",
+ "End"};
+
+ orientation_ = CreateCombobox(base::ASCIIToUTF16("Orientation"),
+ orientation_values, 2, &vertical_pos);
+ main_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Main axis"),
+ main_axis_values, 3, &vertical_pos);
+ cross_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Cross axis"),
+ cross_axis_values, 4, &vertical_pos);
+
+ CreateMarginsTextFields(base::ASCIIToUTF16("Interior margin"),
+ interior_margin_, &vertical_pos);
+
+ CreateMarginsTextFields(base::ASCIIToUTF16("Default margins"),
+ default_child_margins_, &vertical_pos);
+
+ collapse_margins_ =
+ CreateCheckbox(base::ASCIIToUTF16("Collapse margins"), &vertical_pos);
+
+ layout_ = layout_panel()->SetLayoutManager(std::make_unique<FlexLayout>());
+}
+
+void FlexLayoutExample::OnPerformAction(Combobox* combobox) {
+ static const LayoutOrientation orientations[2] = {
+ LayoutOrientation::kHorizontal, LayoutOrientation::kVertical};
+ static const LayoutAlignment main_axis_alignments[3] = {
+ LayoutAlignment::kStart, LayoutAlignment::kCenter, LayoutAlignment::kEnd};
+ static const LayoutAlignment cross_axis_alignments[4] = {
+ LayoutAlignment::kStretch, LayoutAlignment::kStart,
+ LayoutAlignment::kCenter, LayoutAlignment::kEnd};
+
+ if (combobox == orientation_) {
+ layout_->SetOrientation(orientations[combobox->selected_index()]);
+ } else if (combobox == main_axis_alignment_) {
+ layout_->SetMainAxisAlignment(
+ main_axis_alignments[combobox->selected_index()]);
+ } else if (combobox == cross_axis_alignment_) {
+ layout_->SetCrossAxisAlignment(
+ cross_axis_alignments[combobox->selected_index()]);
+ }
+ RefreshLayoutPanel(false);
+}
+
+void FlexLayoutExample::ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) {
+ layout_->SetInteriorMargin(
+ LayoutExampleBase::TextfieldsToInsets(interior_margin_));
+ layout_->SetDefaultChildMargins(
+ LayoutExampleBase::TextfieldsToInsets(default_child_margins_));
+ RefreshLayoutPanel(false);
+}
+
+void FlexLayoutExample::ButtonPressedImpl(Button* sender) {
+ if (sender == collapse_margins_)
+ layout_->SetCollapseMargins(collapse_margins_->checked());
+ RefreshLayoutPanel(false);
+}
+
+void FlexLayoutExample::UpdateLayoutManager() {
+ for (int i = 0; i < layout_panel()->child_count(); ++i) {
+ ChildPanel* panel = static_cast<ChildPanel*>(layout_panel()->child_at(i));
+ int flex = panel->GetFlex();
+ if (flex < 0)
+ layout_->ClearFlexForView(panel);
+ else
+ layout_->SetFlexForView(panel, GetFlexSpecification(flex));
+ }
+}
+
+FlexSpecification FlexLayoutExample::GetFlexSpecification(int weight) const {
+ return weight > 0
+ ? FlexSpecification::ForSizeRule(MinimumFlexSizeRule::kScaleToZero,
+ MaximumFlexSizeRule::kUnbounded)
+ .WithWeight(weight)
+ : FlexSpecification::ForSizeRule(
+ MinimumFlexSizeRule::kPreferredSnapToZero,
+ MaximumFlexSizeRule::kPreferred)
+ .WithWeight(0);
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/flex_layout_example.h b/chromium/ui/views/examples/flex_layout_example.h
new file mode 100644
index 00000000000..de012a2ea5a
--- /dev/null
+++ b/chromium/ui/views/examples/flex_layout_example.h
@@ -0,0 +1,58 @@
+// 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_EXAMPLES_FLEX_LAYOUT_EXAMPLE_H_
+#define UI_VIEWS_EXAMPLES_FLEX_LAYOUT_EXAMPLE_H_
+
+#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/layout_example_base.h"
+#include "ui/views/layout/flex_layout.h"
+
+namespace views {
+
+class Checkbox;
+class Combobox;
+class Textfield;
+
+namespace examples {
+
+class VIEWS_EXAMPLES_EXPORT FlexLayoutExample : public LayoutExampleBase {
+ public:
+ FlexLayoutExample();
+ ~FlexLayoutExample() override;
+
+ private:
+ // ComboboxListener
+ void OnPerformAction(Combobox* combobox) override;
+
+ // TextfieldController
+ void ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) override;
+
+ // LayoutExampleBase
+ void ButtonPressedImpl(Button* sender) override;
+ void CreateAdditionalControls(int vertical_start_pos) override;
+ void UpdateLayoutManager() override;
+
+ FlexSpecification GetFlexSpecification(int weight) const;
+
+ FlexLayout* layout_ = nullptr;
+ Combobox* orientation_ = nullptr;
+ Combobox* main_axis_alignment_ = nullptr;
+ Combobox* cross_axis_alignment_ = nullptr;
+ Checkbox* collapse_margins_ = nullptr;
+ Textfield* interior_margin_[4] = {nullptr, nullptr, nullptr, nullptr};
+ Textfield* default_child_margins_[4] = {nullptr, nullptr, nullptr, nullptr};
+
+ DISALLOW_COPY_AND_ASSIGN(FlexLayoutExample);
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_FLEX_LAYOUT_EXAMPLE_H_
diff --git a/chromium/ui/views/examples/label_example.cc b/chromium/ui/views/examples/label_example.cc
index 87189250851..c9cf287bb4c 100644
--- a/chromium/ui/views/examples/label_example.cc
+++ b/chromium/ui/views/examples/label_example.cc
@@ -6,8 +6,8 @@
#include <memory>
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/vector2d.h"
@@ -181,15 +181,15 @@ void LabelExample::AddCustomLabel(View* container) {
textfield_ = new Textfield();
textfield_->SetText(ASCIIToUTF16("Use the provided controls to configure the "
"content and presentation of this custom label."));
- textfield_->SetSelectionRange(gfx::Range());
+ textfield_->SetEditableSelectionRange(gfx::Range());
textfield_->set_controller(this);
layout->AddView(textfield_);
- alignment_ = AddCombobox(layout, "Alignment: ", kAlignments,
- arraysize(kAlignments));
+ alignment_ =
+ AddCombobox(layout, "Alignment: ", kAlignments, base::size(kAlignments));
elide_behavior_ = AddCombobox(
layout, "Elide Behavior: ", ExamplePreferredSizeLabel::kElideBehaviors,
- arraysize(ExamplePreferredSizeLabel::kElideBehaviors));
+ base::size(ExamplePreferredSizeLabel::kElideBehaviors));
column_set = layout->AddColumnSet(1);
column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
diff --git a/chromium/ui/views/examples/multiline_example.cc b/chromium/ui/views/examples/multiline_example.cc
index 7ecd6834d67..02995b865b6 100644
--- a/chromium/ui/views/examples/multiline_example.cc
+++ b/chromium/ui/views/examples/multiline_example.cc
@@ -97,9 +97,9 @@ class MultilineExample::RenderTextView : public View {
render_text_->SetText(new_contents);
render_text_->SetColor(SK_ColorBLACK);
render_text_->ApplyColor(0xFFFF0000, color_range);
- render_text_->SetStyle(gfx::UNDERLINE, false);
- render_text_->ApplyStyle(gfx::UNDERLINE, true, color_range);
- render_text_->ApplyStyle(gfx::ITALIC, true, italic_range);
+ render_text_->SetStyle(gfx::TEXT_STYLE_UNDERLINE, false);
+ render_text_->ApplyStyle(gfx::TEXT_STYLE_UNDERLINE, true, color_range);
+ render_text_->ApplyStyle(gfx::TEXT_STYLE_ITALIC, true, italic_range);
render_text_->ApplyWeight(gfx::Font::Weight::BOLD, bold_range);
InvalidateLayout();
}
diff --git a/chromium/ui/views/examples/radio_button_example.cc b/chromium/ui/views/examples/radio_button_example.cc
index 65826da1509..086dbfac697 100644
--- a/chromium/ui/views/examples/radio_button_example.cc
+++ b/chromium/ui/views/examples/radio_button_example.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/views/controls/button/label_button.h"
@@ -27,7 +27,7 @@ void RadioButtonExample::CreateExampleView(View* container) {
status_ = new LabelButton(this, base::ASCIIToUTF16("Show Status"));
int group = 1;
- for (size_t i = 0; i < arraysize(radio_buttons_); ++i) {
+ for (size_t i = 0; i < base::size(radio_buttons_); ++i) {
radio_buttons_[i] = new RadioButton(
base::UTF8ToUTF16(base::StringPrintf(
"Radio %d in group %d", static_cast<int>(i) + 1, group)),
@@ -40,7 +40,7 @@ void RadioButtonExample::CreateExampleView(View* container) {
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL,
1.0f, GridLayout::USE_PREF, 0, 0);
- for (size_t i = 0; i < arraysize(radio_buttons_); ++i) {
+ for (size_t i = 0; i < base::size(radio_buttons_); ++i) {
layout->StartRow(0, 0);
layout->AddView(radio_buttons_[i]);
}
diff --git a/chromium/ui/views/examples/text_example.cc b/chromium/ui/views/examples/text_example.cc
index c37608c4f2e..b9992899fcd 100644
--- a/chromium/ui/views/examples/text_example.cc
+++ b/chromium/ui/views/examples/text_example.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font_list.h"
@@ -170,15 +170,15 @@ void TextExample::CreateExampleView(View* container) {
column_set->AddPaddingColumn(0, 8);
h_align_cb_ = AddCombobox(layout, "H-Align", kHorizontalAligments,
- arraysize(kHorizontalAligments));
+ base::size(kHorizontalAligments));
eliding_cb_ = AddCombobox(layout, "Eliding", kElideBehaviors,
- arraysize(kElideBehaviors));
- prefix_cb_ = AddCombobox(layout, "Prefix", kPrefixOptions,
- arraysize(kPrefixOptions));
+ base::size(kElideBehaviors));
+ prefix_cb_ =
+ AddCombobox(layout, "Prefix", kPrefixOptions, base::size(kPrefixOptions));
text_cb_ = AddCombobox(layout, "Example Text", kTextExamples,
- arraysize(kTextExamples));
+ base::size(kTextExamples));
weight_cb_ = AddCombobox(layout, "Font Weight", kWeightLabels,
- arraysize(kWeightLabels));
+ base::size(kWeightLabels));
weight_cb_->SelectValue(base::ASCIIToUTF16("Normal"));
layout->StartRow(0, 0);
diff --git a/chromium/ui/views/examples/textfield_example.cc b/chromium/ui/views/examples/textfield_example.cc
index 8217a52d909..73cde0b5b5f 100644
--- a/chromium/ui/views/examples/textfield_example.cc
+++ b/chromium/ui/views/examples/textfield_example.cc
@@ -150,12 +150,12 @@ void TextfieldExample::ButtonPressed(Button* sender, const ui::Event& event) {
if (name_->text().length() >= 5) {
size_t fifth = name_->text().length() / 5;
const gfx::Range big_range(1 * fifth, 4 * fifth);
- name_->ApplyStyle(gfx::UNDERLINE, true, big_range);
+ name_->ApplyStyle(gfx::TEXT_STYLE_UNDERLINE, true, big_range);
name_->ApplyColor(SK_ColorBLUE, big_range);
const gfx::Range small_range(2 * fifth, 3 * fifth);
- name_->ApplyStyle(gfx::ITALIC, true, small_range);
- name_->ApplyStyle(gfx::UNDERLINE, false, small_range);
+ name_->ApplyStyle(gfx::TEXT_STYLE_ITALIC, true, small_range);
+ name_->ApplyStyle(gfx::TEXT_STYLE_UNDERLINE, false, small_range);
name_->ApplyColor(SK_ColorRED, small_range);
}
}
diff --git a/chromium/ui/views/focus/focus_manager_factory.cc b/chromium/ui/views/focus/focus_manager_factory.cc
index 5ebe513b2e3..9a63c416054 100644
--- a/chromium/ui/views/focus/focus_manager_factory.cc
+++ b/chromium/ui/views/focus/focus_manager_factory.cc
@@ -13,13 +13,11 @@ namespace {
class DefaultFocusManagerFactory : public FocusManagerFactory {
public:
- DefaultFocusManagerFactory() : FocusManagerFactory() {}
- ~DefaultFocusManagerFactory() override {}
+ DefaultFocusManagerFactory() = default;
+ ~DefaultFocusManagerFactory() override = default;
protected:
- std::unique_ptr<FocusManager> CreateFocusManager(
- Widget* widget,
- bool desktop_widget) override {
+ std::unique_ptr<FocusManager> CreateFocusManager(Widget* widget) override {
return std::make_unique<FocusManager>(widget, nullptr /* delegate */);
}
@@ -31,18 +29,15 @@ FocusManagerFactory* g_focus_manager_factory = nullptr;
} // namespace
-FocusManagerFactory::FocusManagerFactory() {
-}
+FocusManagerFactory::FocusManagerFactory() = default;
-FocusManagerFactory::~FocusManagerFactory() {
-}
+FocusManagerFactory::~FocusManagerFactory() = default;
// static
-std::unique_ptr<FocusManager> FocusManagerFactory::Create(Widget* widget,
- bool desktop_widget) {
+std::unique_ptr<FocusManager> FocusManagerFactory::Create(Widget* widget) {
if (!g_focus_manager_factory)
g_focus_manager_factory = new DefaultFocusManagerFactory();
- return g_focus_manager_factory->CreateFocusManager(widget, desktop_widget);
+ return g_focus_manager_factory->CreateFocusManager(widget);
}
// static
diff --git a/chromium/ui/views/focus/focus_manager_factory.h b/chromium/ui/views/focus/focus_manager_factory.h
index 9b17a8cbec7..1a91b9e1d49 100644
--- a/chromium/ui/views/focus/focus_manager_factory.h
+++ b/chromium/ui/views/focus/focus_manager_factory.h
@@ -20,8 +20,7 @@ class Widget;
class VIEWS_EXPORT FocusManagerFactory {
public:
// Create a FocusManager for the given |widget| using the installed Factory.
- static std::unique_ptr<FocusManager> Create(Widget* widget,
- bool desktop_widget);
+ static std::unique_ptr<FocusManager> Create(Widget* widget);
// Installs FocusManagerFactory. If |factory| is NULL, it resets
// to the default factory which creates plain FocusManager.
@@ -32,11 +31,7 @@ class VIEWS_EXPORT FocusManagerFactory {
virtual ~FocusManagerFactory();
// Create a FocusManager for the given |widget|.
- // The |desktop_widget| bool is true for widgets created in the desktop and
- // false for widgets created in the shell.
- virtual std::unique_ptr<FocusManager> CreateFocusManager(
- Widget* widget,
- bool desktop_widget) = 0;
+ virtual std::unique_ptr<FocusManager> CreateFocusManager(Widget* widget) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(FocusManagerFactory);
diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc
index 0ee56a6217d..ece8d06808f 100644
--- a/chromium/ui/views/focus/focus_manager_unittest.cc
+++ b/chromium/ui/views/focus/focus_manager_unittest.cc
@@ -437,9 +437,7 @@ class FocusManagerDtorTest : public FocusManagerTest {
: dtor_tracker_(dtor_tracker) {}
~TestFocusManagerFactory() override {}
- std::unique_ptr<FocusManager> CreateFocusManager(
- Widget* widget,
- bool desktop_widget) override {
+ std::unique_ptr<FocusManager> CreateFocusManager(Widget* widget) override {
return std::make_unique<FocusManagerDtorTracked>(widget, dtor_tracker_);
}
@@ -838,7 +836,7 @@ class TestBubbleDialogDelegateView : public BubbleDialogDelegateView {
// platform and other factors.
void UseNativeWidgetAura() { use_native_widget_aura_ = true; }
- // ui::DialogModel override.
+ // BubbleDialogDelegateView:
int GetDialogButtons() const override { return 0; }
void OnBeforeBubbleWidgetInit(Widget::InitParams* params,
@@ -1041,19 +1039,64 @@ TEST_F(FocusManagerTest, AnchoredDialogOnContainerView) {
EXPECT_TRUE(parent3->HasFocus());
}
-// Desktop native widget Aura tests are for non Chrome OS platforms.
+// Checks that focus traverses from a View to a bubble anchored at that View
+// when in a pane.
+TEST_F(FocusManagerTest, AnchoredDialogInPane) {
+ // Set up a focusable view (to which we will anchor our bubble) inside an
+ // AccessiblePaneView.
+ View* root_view = GetWidget()->GetRootView();
+ AccessiblePaneView* pane =
+ root_view->AddChildView(std::make_unique<AccessiblePaneView>());
+ View* anchor = pane->AddChildView(std::make_unique<View>());
+ anchor->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+
+ BubbleDialogDelegateView* bubble = new TestBubbleDialogDelegateView(anchor);
+ test::WidgetTest::WidgetAutoclosePtr bubble_widget(
+ BubbleDialogDelegateView::CreateBubble(bubble));
+ bubble_widget->SetFocusTraversableParent(
+ bubble->anchor_widget()->GetFocusTraversable());
+ bubble_widget->SetFocusTraversableParentView(anchor);
+ bubble->set_close_on_deactivate(false);
+ bubble_widget->Show();
+
+ // We need a focusable view inside our bubble to check that focus traverses
+ // in.
+ View* bubble_child = bubble->AddChildView(std::make_unique<View>());
+ bubble_child->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+
+ // Verify that, when in pane focus mode, focus advances from the anchor view
+ // to inside the bubble.
+ pane->SetPaneFocus(anchor);
+ EXPECT_TRUE(anchor->HasFocus());
+ GetWidget()->GetFocusManager()->AdvanceFocus(false);
+ EXPECT_TRUE(bubble_child->HasFocus());
+}
+
// This test is specifically for the permutation where the main
// widget is a DesktopNativeWidgetAura and the bubble is a
// NativeWidgetAura. When focus moves back from the bubble to the
// parent widget, ensure that the DNWA's aura window is focused.
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
-TEST_F(FocusManagerTest, AnchoredDialogInDesktopNativeWidgetAura) {
+#if defined(USE_AURA)
+class DesktopWidgetFocusManagerTest : public FocusManagerTest {
+ public:
+ DesktopWidgetFocusManagerTest() = default;
+ ~DesktopWidgetFocusManagerTest() override = default;
+
+ // FocusManagerTest:
+ void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+ FocusManagerTest::SetUp();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopWidgetFocusManagerTest);
+};
+
+TEST_F(DesktopWidgetFocusManagerTest, AnchoredDialogInDesktopNativeWidgetAura) {
Widget widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(0, 0, 1024, 768);
- params.native_widget =
- test::CreatePlatformDesktopNativeWidgetImpl(params, &widget, nullptr);
widget.Init(params);
widget.Show();
widget.Activate();
@@ -1108,6 +1151,40 @@ TEST_F(FocusManagerTest, AnchoredDialogInDesktopNativeWidgetAura) {
// Finally, the outer widget's window should be focused again.
ASSERT_EQ(widget.GetNativeView(), focus_client->GetFocusedWindow());
}
-#endif // defined(USE_AURA) && !defined(OS_CHROMEOS)
+#endif // defined(USE_AURA)
+
+// Ensures graceful failure if there is a focus cycle.
+TEST_F(FocusManagerTest, HandlesFocusCycles) {
+ // Create two side-by-side views.
+ View* root_view = GetWidget()->GetRootView();
+ View* left = root_view->AddChildView(std::make_unique<View>());
+ View* right = root_view->AddChildView(std::make_unique<View>());
+
+ // Create a cycle where the left view is focusable and the right isn't.
+ left->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+ right->SetFocusBehavior(View::FocusBehavior::NEVER);
+ left->SetNextFocusableView(right);
+ right->SetNextFocusableView(left);
+
+ // Set focus on the left view then make it unfocusable, which both advances
+ // focus and ensures there's no candidate for focusing.
+ left->RequestFocus();
+ EXPECT_TRUE(left->HasFocus());
+ left->SetFocusBehavior(View::FocusBehavior::NEVER);
+
+ // At this point, we didn't crash. Just as a sanity check, ensure neither of
+ // our views were incorrectly focused.
+ EXPECT_FALSE(left->HasFocus());
+ EXPECT_FALSE(right->HasFocus());
+
+ // Now test focusing in reverse.
+ GetFocusManager()->SetFocusedView(right);
+ EXPECT_TRUE(right->HasFocus());
+ GetFocusManager()->AdvanceFocus(true);
+
+ // We don't check whether |right| has focus since if no focusable view is
+ // found, AdvanceFocus() doesn't clear focus.
+ EXPECT_FALSE(left->HasFocus());
+}
} // namespace views
diff --git a/chromium/ui/views/focus/focus_search.cc b/chromium/ui/views/focus/focus_search.cc
index 8351f8f9225..f10a62b682c 100644
--- a/chromium/ui/views/focus/focus_search.cc
+++ b/chromium/ui/views/focus/focus_search.cc
@@ -60,27 +60,39 @@ View* FocusSearch::FindNextFocusableView(
DCHECK(Contains(root_, starting_view));
}
+ base::flat_set<View*> seen_views;
View* v = nullptr;
if (search_direction == SearchDirection::kForwards) {
v = FindNextFocusableViewImpl(
starting_view, check_starting_view, true,
- (traversal_direction == TraversalDirection::kDown), starting_view_group,
+ (traversal_direction == TraversalDirection::kDown),
+ can_go_into_anchored_dialog, starting_view_group, &seen_views,
focus_traversable, focus_traversable_view);
} else {
// If the starting view is focusable, we don't want to go down, as we are
// traversing the view hierarchy tree bottom-up.
bool can_go_down = (traversal_direction == TraversalDirection::kDown) &&
!IsFocusable(starting_view);
- v = FindPreviousFocusableViewImpl(starting_view, check_starting_view, true,
- can_go_down, can_go_into_anchored_dialog,
- starting_view_group, focus_traversable,
- focus_traversable_view);
+ v = FindPreviousFocusableViewImpl(
+ starting_view, check_starting_view, true, can_go_down,
+ can_go_into_anchored_dialog, starting_view_group, &seen_views,
+ focus_traversable, focus_traversable_view);
}
// Don't set the focus to something outside of this view hierarchy.
if (v && v != root_ && !Contains(root_, v))
v = nullptr;
+ // If we should go into a sub-FocusTraversable (such as an anchored bubble), a
+ // null View is returned and |focus_traversable| is set appropriately. Handle
+ // this case before cycling. Note that Find{Next,Previous}FocusableViewImpl
+ // respect |can_go_into_anchored_dialog| so we don't need to check it here.
+ if (*focus_traversable) {
+ DCHECK(*focus_traversable_view);
+ DCHECK_EQ(v, nullptr);
+ return nullptr;
+ }
+
// If |cycle_| is true, prefer to keep cycling rather than returning nullptr.
if (cycle_ && !v && initial_starting_view) {
v = FindNextFocusableView(nullptr, search_direction, traversal_direction,
@@ -95,10 +107,7 @@ View* FocusSearch::FindNextFocusableView(
DCHECK(IsFocusable(v));
return v;
}
- if (*focus_traversable) {
- DCHECK(*focus_traversable_view);
- return nullptr;
- }
+
// Nothing found.
return nullptr;
}
@@ -155,9 +164,19 @@ View* FocusSearch::FindNextFocusableViewImpl(
FocusSearch::StartingViewPolicy check_starting_view,
bool can_go_up,
bool can_go_down,
+ AnchoredDialogPolicy can_go_into_anchored_dialog,
int skip_group_id,
+ base::flat_set<View*>* seen_views,
FocusTraversable** focus_traversable,
View** focus_traversable_view) {
+ // Views are not supposed to have focus cycles, but just in case, fail
+ // gracefully to avoid a crash.
+ if (seen_views->contains(starting_view)) {
+ LOG(ERROR) << "View focus cycle detected.";
+ return nullptr;
+ }
+ seen_views->insert(starting_view);
+
if (check_starting_view == StartingViewPolicy::kCheckStartingView) {
if (IsViewFocusableCandidate(starting_view, skip_group_id)) {
View* v = FindSelectedViewForGroup(starting_view);
@@ -179,18 +198,22 @@ View* FocusSearch::FindNextFocusableViewImpl(
if (starting_view->has_children()) {
View* v = FindNextFocusableViewImpl(
starting_view->child_at(0), StartingViewPolicy::kCheckStartingView,
- false, true, skip_group_id, focus_traversable,
- focus_traversable_view);
+ false, true, can_go_into_anchored_dialog, skip_group_id, seen_views,
+ focus_traversable, focus_traversable_view);
if (v || *focus_traversable)
return v;
}
+
// 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;
+ if (can_go_into_anchored_dialog ==
+ AnchoredDialogPolicy::kCanGoIntoAnchoredDialog) {
+ BubbleDialogDelegateView* bubble =
+ starting_view->GetProperty(kAnchoredDialogKey);
+ if (bubble) {
+ *focus_traversable = bubble->GetWidget()->GetFocusTraversable();
+ *focus_traversable_view = starting_view;
+ return nullptr;
+ }
}
}
@@ -199,7 +222,8 @@ View* FocusSearch::FindNextFocusableViewImpl(
if (sibling) {
View* v = FindNextFocusableViewImpl(
sibling, FocusSearch::StartingViewPolicy::kCheckStartingView, false,
- true, skip_group_id, focus_traversable, focus_traversable_view);
+ true, can_go_into_anchored_dialog, skip_group_id, seen_views,
+ focus_traversable, focus_traversable_view);
if (v || *focus_traversable)
return v;
}
@@ -208,19 +232,23 @@ View* FocusSearch::FindNextFocusableViewImpl(
if (can_go_up) {
View* parent = GetParent(starting_view);
while (parent && parent != root_) {
- BubbleDialogDelegateView* bubble =
- parent->GetProperty(kAnchoredDialogKey);
- if (bubble) {
- *focus_traversable = bubble->GetWidget()->GetFocusTraversable();
- *focus_traversable_view = starting_view;
- return nullptr;
+ if (can_go_into_anchored_dialog ==
+ AnchoredDialogPolicy::kCanGoIntoAnchoredDialog) {
+ BubbleDialogDelegateView* bubble =
+ parent->GetProperty(kAnchoredDialogKey);
+ if (bubble) {
+ *focus_traversable = bubble->GetWidget()->GetFocusTraversable();
+ *focus_traversable_view = starting_view;
+ return nullptr;
+ }
}
sibling = parent->GetNextFocusableView();
if (sibling) {
return FindNextFocusableViewImpl(
sibling, StartingViewPolicy::kCheckStartingView, true, true,
- skip_group_id, focus_traversable, focus_traversable_view);
+ can_go_into_anchored_dialog, skip_group_id, seen_views,
+ focus_traversable, focus_traversable_view);
}
parent = GetParent(parent);
}
@@ -243,8 +271,17 @@ View* FocusSearch::FindPreviousFocusableViewImpl(
bool can_go_down,
FocusSearch::AnchoredDialogPolicy can_go_into_anchored_dialog,
int skip_group_id,
+ base::flat_set<View*>* seen_views,
FocusTraversable** focus_traversable,
View** focus_traversable_view) {
+ // Views are not supposed to have focus cycles, but just in case, fail
+ // gracefully to avoid a crash.
+ if (seen_views->contains(starting_view)) {
+ LOG(ERROR) << "View focus cycle detected.";
+ return nullptr;
+ }
+ seen_views->insert(starting_view);
+
// Normally when we navigate to a FocusTraversableParent, can_go_down is
// false so we don't navigate back in. However, if we just navigated out
// of an anchored dialog, allow going down in order to navigate into
@@ -285,8 +322,8 @@ View* FocusSearch::FindPreviousFocusableViewImpl(
starting_view->child_at(starting_view->child_count() - 1);
View* v = FindPreviousFocusableViewImpl(
view, StartingViewPolicy::kCheckStartingView, false, true,
- can_go_into_anchored_dialog, skip_group_id, focus_traversable,
- focus_traversable_view);
+ can_go_into_anchored_dialog, skip_group_id, seen_views,
+ focus_traversable, focus_traversable_view);
if (v || *focus_traversable)
return v;
}
@@ -308,8 +345,8 @@ View* FocusSearch::FindPreviousFocusableViewImpl(
if (sibling) {
return FindPreviousFocusableViewImpl(
sibling, StartingViewPolicy::kCheckStartingView, can_go_up, true,
- can_go_into_anchored_dialog, skip_group_id, focus_traversable,
- focus_traversable_view);
+ can_go_into_anchored_dialog, skip_group_id, seen_views,
+ focus_traversable, focus_traversable_view);
}
// Then go up the parent.
@@ -318,8 +355,8 @@ View* FocusSearch::FindPreviousFocusableViewImpl(
if (parent)
return FindPreviousFocusableViewImpl(
parent, StartingViewPolicy::kCheckStartingView, true, false,
- can_go_into_anchored_dialog, skip_group_id, focus_traversable,
- focus_traversable_view);
+ can_go_into_anchored_dialog, skip_group_id, seen_views,
+ focus_traversable, focus_traversable_view);
}
// We found nothing.
diff --git a/chromium/ui/views/focus/focus_search.h b/chromium/ui/views/focus/focus_search.h
index 4d315449d54..ca05b86eab8 100644
--- a/chromium/ui/views/focus/focus_search.h
+++ b/chromium/ui/views/focus/focus_search.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_FOCUS_FOCUS_SEARCH_H_
#define UI_VIEWS_FOCUS_FOCUS_SEARCH_H_
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "ui/views/view.h"
@@ -122,13 +123,16 @@ class VIEWS_EXPORT FocusSearch {
// |check_starting_view|, |can_go_up| and |can_go_down| controls the
// traversal of the views hierarchy. |skip_group_id| specifies a group_id,
// -1 means no group. All views from a group are traversed in one pass.
- View* FindNextFocusableViewImpl(View* starting_view,
- StartingViewPolicy check_starting_view,
- bool can_go_up,
- bool can_go_down,
- int skip_group_id,
- FocusTraversable** focus_traversable,
- View** focus_traversable_view);
+ View* FindNextFocusableViewImpl(
+ View* starting_view,
+ StartingViewPolicy check_starting_view,
+ bool can_go_up,
+ bool can_go_down,
+ AnchoredDialogPolicy can_go_into_anchored_dialog,
+ int skip_group_id,
+ base::flat_set<View*>* seen_views,
+ FocusTraversable** focus_traversable,
+ View** focus_traversable_view);
// Same as FindNextFocusableViewImpl but returns the previous focusable view.
View* FindPreviousFocusableViewImpl(
@@ -138,6 +142,7 @@ class VIEWS_EXPORT FocusSearch {
bool can_go_down,
AnchoredDialogPolicy can_go_into_anchored_dialog,
int skip_group_id,
+ base::flat_set<View*>* seen_views,
FocusTraversable** focus_traversable,
View** focus_traversable_view);
diff --git a/chromium/ui/views/focus/focus_traversal_unittest.cc b/chromium/ui/views/focus/focus_traversal_unittest.cc
index 2e45e0ab16d..4a3cd7e0c06 100644
--- a/chromium/ui/views/focus/focus_traversal_unittest.cc
+++ b/chromium/ui/views/focus/focus_traversal_unittest.cc
@@ -4,8 +4,8 @@
#include <stddef.h>
-#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/models/combobox_model.h"
@@ -455,10 +455,10 @@ void FocusTraversalTest::InitContentView() {
CAMPING_LINK_ID, BRICE_DE_NICE_LINK_ID,
TAXI_LINK_ID, ASTERIX_LINK_ID};
- DCHECK(arraysize(kTitles) == arraysize(kIDs));
+ DCHECK(base::size(kTitles) == base::size(kIDs));
y = 5;
- for (size_t i = 0; i < arraysize(kTitles); ++i) {
+ for (size_t i = 0; i < base::size(kTitles); ++i) {
Link* link = new Link(ASCIIToUTF16(kTitles[i]));
link->SetHorizontalAlignment(gfx::ALIGN_LEFT);
link->set_id(kIDs[i]);
@@ -704,7 +704,7 @@ TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) {
SCOPED_TRACE("TraversalWithNonEnabledViews");
// Let's disable some views.
- for (size_t i = 0; i < arraysize(kDisabledIDs); i++) {
+ for (size_t i = 0; i < base::size(kDisabledIDs); i++) {
View* v = FindViewByID(kDisabledIDs[i]);
ASSERT_TRUE(v != NULL);
v->SetEnabled(false);
@@ -744,7 +744,7 @@ TEST_F(FocusTraversalTest, TraversalWithInvisibleViews) {
SCOPED_TRACE("TraversalWithInvisibleViews");
// Let's make some views invisible.
- for (size_t i = 0; i < arraysize(kInvisibleIDs); i++) {
+ for (size_t i = 0; i < base::size(kInvisibleIDs); i++) {
View* v = FindViewByID(kInvisibleIDs[i]);
ASSERT_TRUE(v != NULL);
v->SetVisible(false);
diff --git a/chromium/ui/views/mus/interactive_ui_tests_manifest.json b/chromium/ui/views/interactive_ui_tests_manifest.json
index 36a5b66daf1..567ca61b530 100644
--- a/chromium/ui/views/mus/interactive_ui_tests_manifest.json
+++ b/chromium/ui/views/interactive_ui_tests_manifest.json
@@ -1,6 +1,6 @@
{
- "name": "views_mus_interactive_ui_tests",
- "display_name": "Views Mus Interactive UI Tests",
+ "name": "interactive_ui_tests",
+ "display_name": "Interactive UI Tests",
"interface_provider_specs": {
"service_manager:connector": {
"requires": {
diff --git a/chromium/ui/views/layout/OWNERS b/chromium/ui/views/layout/OWNERS
new file mode 100644
index 00000000000..b4ee07df6fa
--- /dev/null
+++ b/chromium/ui/views/layout/OWNERS
@@ -0,0 +1 @@
+per-file flex_layout*=dfried@chromium.org \ No newline at end of file
diff --git a/chromium/ui/views/layout/flex_layout.cc b/chromium/ui/views/layout/flex_layout.cc
new file mode 100644
index 00000000000..ca5e6640de7
--- /dev/null
+++ b/chromium/ui/views/layout/flex_layout.cc
@@ -0,0 +1,1044 @@
+// 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/layout/flex_layout.h"
+
+#include <algorithm>
+#include <functional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "ui/events/event_target.h"
+#include "ui/events/event_target_iterator.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/layout/flex_layout_types.h"
+#include "ui/views/layout/flex_layout_types_internal.h"
+#include "ui/views/view.h"
+#include "ui/views/view_properties.h"
+
+// Module-private declarations -------------------------------------------------
+
+namespace views {
+
+namespace internal {
+
+namespace {
+
+// Layout information for a specific child view in a proposed layout.
+struct ChildLayout {
+ ChildLayout(View* view, const FlexSpecification& flex)
+ : view(view), flex(flex) {}
+ ChildLayout(ChildLayout&& other) = default;
+
+ View* view = nullptr;
+ bool excluded = false;
+ // Indicates whether external code has called SetVisible(false) on the view.
+ bool hidden_by_owner = false;
+ // Indicates whether the layout has chosen to display this child view.
+ bool visible = false;
+ // Start with zero size rather than unspecified size bounds because we start
+ // all layouts with controls at their minimum allowed sizes.
+ NormalizedSizeBounds available_size{0, 0};
+ NormalizedSize preferred_size;
+ NormalizedSize current_size;
+ NormalizedRect actual_bounds;
+ NormalizedInsets margins;
+ NormalizedInsets internal_padding;
+ FlexSpecification flex;
+
+ private:
+ // Copying this struct would be expensive and they only ever live in a vector
+ // in Layout (see below) so we'll only allow move semantics.
+ DISALLOW_COPY_AND_ASSIGN(ChildLayout);
+};
+
+// Represents a specific stored layout given a set of size bounds.
+struct Layout {
+ explicit Layout(int64_t layout_counter) : layout_id(layout_counter) {}
+
+ // Indicates which layout pass this layout was created/last validated on. If
+ // this number disagrees with FlexLayoutInternal::layout_counter_, we need to
+ // re-validate the layout before using it.
+ mutable uint32_t layout_id;
+ std::vector<ChildLayout> child_layouts;
+ NormalizedInsets interior_margin;
+ NormalizedSizeBounds available_size;
+ NormalizedSize total_size;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Layout);
+};
+
+// Preserves layouts for common layout requests, because we may be asked to
+// recompute them many times but don't want to repeat the calculation.
+//
+// Specifically, we will be asked for:
+// - The layout's minimum size (bounds = {0, 0})
+// - The layout's preferred size (neither bound specified)
+// - The final layout at the dimensions of the host view (both bounds nonzero)
+//
+// There is also the possibility of a view with a flex layout being embedded in
+// a view with a flex layout, where the inner view has a nontrivial flex
+// specification. In that case, in order to handle e.g. labels in the inner
+// view, the outer layout manager will ask for the inner view's preferred height
+// for its width, which potentially involves another layout calculation.
+// However, these calculations are transient - they only happen when the layout
+// is recalculated or validated, and in the latter case only one set of bounds
+// is evaluated. So we will keep exactly one of these layouts around.
+//
+// As a first pass, we'll store all of these specifically. In the future we can
+// switch to using something more sophisticated, like an MRU cache, if we find
+// we're thrashing for some other reason.
+class LayoutCache {
+ public:
+ // Removes all saved layouts.
+ void Clear() {
+ minimum_.reset();
+ preferred_.reset();
+ intermediate_.layout.reset();
+ current_.layout.reset();
+ }
+
+ // Gets a cached layout, or nullptr if no layout is cached for the specified
+ // bounds.
+ Layout* Get(const NormalizedSizeBounds& bounds) const {
+ if (bounds == NormalizedSizeBounds(0, 0))
+ return minimum_.get();
+ if (bounds == NormalizedSizeBounds())
+ return preferred_.get();
+ if (bounds == intermediate_.bounds)
+ return intermediate_.layout.get();
+ if (bounds == current_.bounds)
+ return current_.layout.get();
+ return nullptr;
+ }
+
+ // Caches a layout associated with the specified bounds.
+ void Put(const NormalizedSizeBounds& bounds, std::unique_ptr<Layout> layout) {
+ if (bounds == NormalizedSizeBounds(0, 0)) {
+ minimum_ = std::move(layout);
+ } else if (bounds == NormalizedSizeBounds()) {
+ preferred_ = std::move(layout);
+ } else if (!bounds.cross() || !bounds.main()) {
+ intermediate_.bounds = bounds;
+ intermediate_.layout = std::move(layout);
+ } else {
+ current_.bounds = bounds;
+ current_.layout = std::move(layout);
+ }
+ }
+
+ private:
+ struct CacheEntry {
+ NormalizedSizeBounds bounds;
+ std::unique_ptr<Layout> layout;
+ };
+
+ std::unique_ptr<Layout> minimum_;
+ std::unique_ptr<Layout> preferred_;
+
+ // TODO(dfried): consider replacing these with an MRUCache if this ends up
+ // thrashing a lot (see note above).
+ CacheEntry intermediate_;
+ CacheEntry current_;
+};
+
+// Calculates and maintains 1D spacing between a sequence of child views.
+class ChildViewSpacing {
+ public:
+ // Given the indices of two child views, returns the amount of space that
+ // should be placed between them if they were adjacent. If the first index is
+ // absent, uses the left edge of the parent container. If the second index is
+ // absent, uses the right edge of the parent container.
+ using GetViewSpacingCallback =
+ base::RepeatingCallback<int(base::Optional<int>, base::Optional<int>)>;
+
+ explicit ChildViewSpacing(const GetViewSpacingCallback& get_view_spacing);
+ ChildViewSpacing(ChildViewSpacing&& other);
+ ChildViewSpacing& operator=(ChildViewSpacing&& other);
+
+ bool HasViewIndex(int view_index) const;
+ int GetLeadingInset() const;
+ int GetTrailingInset() const;
+ int GetLeadingSpace(int view_index) const;
+ int GetTrailingSpace(int view_index) const;
+ int GetTotalSpace() const;
+
+ // Returns the change in space required if the specified view index were
+ // added.
+ int GetAddDelta(int view_index) const;
+
+ // Add the view at the specified index.
+ //
+ // If |new_leading| or |new_trailing| is specified, it will be set to the new
+ // leading/trailing space for the view at the index that was added.
+ void AddViewIndex(int view_index,
+ int* new_leading = nullptr,
+ int* new_trailing = nullptr);
+
+ private:
+ base::Optional<int> GetPreviousViewIndex(int view_index) const;
+ base::Optional<int> GetNextViewIndex(int view_index) const;
+
+ GetViewSpacingCallback get_view_spacing_;
+ // Maps from view index to the leading spacing for that index.
+ std::map<int, int> leading_spacings_;
+ // The trailing space (space preceding the trailing margin).
+ int trailing_space_;
+};
+
+ChildViewSpacing::ChildViewSpacing(
+ const GetViewSpacingCallback& get_view_spacing)
+ : get_view_spacing_(get_view_spacing),
+ trailing_space_(
+ get_view_spacing.Run(base::Optional<int>(), base::Optional<int>())) {}
+
+ChildViewSpacing::ChildViewSpacing(ChildViewSpacing&& other)
+ : get_view_spacing_(std::move(other.get_view_spacing_)),
+ leading_spacings_(std::move(other.leading_spacings_)),
+ trailing_space_(other.trailing_space_) {}
+
+ChildViewSpacing& ChildViewSpacing::operator=(ChildViewSpacing&& other) {
+ if (this != &other) {
+ get_view_spacing_ = std::move(other.get_view_spacing_);
+ leading_spacings_ = std::move(other.leading_spacings_);
+ trailing_space_ = other.trailing_space_;
+ }
+ return *this;
+}
+
+bool ChildViewSpacing::HasViewIndex(int view_index) const {
+ return leading_spacings_.find(view_index) != leading_spacings_.end();
+}
+
+int ChildViewSpacing::GetLeadingInset() const {
+ if (leading_spacings_.empty())
+ return 0;
+ return leading_spacings_.begin()->second;
+}
+
+int ChildViewSpacing::GetTrailingInset() const {
+ return trailing_space_;
+}
+
+int ChildViewSpacing::GetLeadingSpace(int view_index) const {
+ auto it = leading_spacings_.find(view_index);
+ DCHECK(it != leading_spacings_.end());
+ return it->second;
+}
+
+int ChildViewSpacing::GetTrailingSpace(int view_index) const {
+ auto it = leading_spacings_.find(view_index);
+ DCHECK(it != leading_spacings_.end());
+ if (++it == leading_spacings_.end())
+ return trailing_space_;
+ return it->second;
+}
+
+int ChildViewSpacing::GetTotalSpace() const {
+ int space = trailing_space_;
+ for (auto& pr : leading_spacings_)
+ space += pr.second;
+ return space;
+}
+
+int ChildViewSpacing::GetAddDelta(int view_index) const {
+ DCHECK(!HasViewIndex(view_index));
+ base::Optional<int> prev = GetPreviousViewIndex(view_index);
+ base::Optional<int> next = GetNextViewIndex(view_index);
+ const int old_spacing = next ? GetLeadingSpace(*next) : GetTrailingInset();
+ const int new_spacing = get_view_spacing_.Run(prev, view_index) +
+ get_view_spacing_.Run(view_index, next);
+ return new_spacing - old_spacing;
+}
+
+void ChildViewSpacing::AddViewIndex(int view_index,
+ int* new_leading,
+ int* new_trailing) {
+ DCHECK(!HasViewIndex(view_index));
+ base::Optional<int> prev = GetPreviousViewIndex(view_index);
+ base::Optional<int> next = GetNextViewIndex(view_index);
+
+ const int leading_space = get_view_spacing_.Run(prev, view_index);
+ const int trailing_space = get_view_spacing_.Run(view_index, next);
+ leading_spacings_[view_index] = leading_space;
+ if (next)
+ leading_spacings_[*next] = trailing_space;
+ else
+ trailing_space_ = trailing_space;
+
+ if (new_leading)
+ *new_leading = leading_space;
+ if (new_trailing)
+ *new_trailing = trailing_space;
+}
+
+base::Optional<int> ChildViewSpacing::GetPreviousViewIndex(
+ int view_index) const {
+ auto it = leading_spacings_.lower_bound(view_index);
+ if (it == leading_spacings_.begin())
+ return base::Optional<int>();
+ return (--it)->first;
+}
+
+base::Optional<int> ChildViewSpacing::GetNextViewIndex(int view_index) const {
+ auto it = leading_spacings_.upper_bound(view_index);
+ if (it == leading_spacings_.end())
+ return base::Optional<int>();
+ return it->first;
+}
+
+// Utility functions -----------------------------------------------------------
+
+gfx::Insets GetInternalPadding(const View* view) {
+ const gfx::Insets* const margins =
+ view->GetProperty(views::kInternalPaddingKey);
+ return margins ? *margins : gfx::Insets();
+}
+
+} // anonymous namespace
+
+// Private implementation ------------------------------------------------------
+
+// Holds child-view-specific layout parameters that are not stored in the
+// properties system.
+//
+// We should consider storing some or all of these in the properites system.
+struct ChildLayoutParams {
+ bool excluded = false;
+ bool hidden_by_owner = false;
+ base::Optional<FlexSpecification> flex_specification;
+};
+
+// Internal data structure and functionality for FlexLayout so we don't have to
+// declare a bunch of classes and data in the .h file.
+class FlexLayoutInternal {
+ public:
+ explicit FlexLayoutInternal(FlexLayout* layout)
+ : layout_(*layout) {} //, cached_layouts_(kMaxCachedLayouts) {}
+
+ // Suggests that the current layout needs to be recalculated. Setting |force|
+ // to true indicates that we know all of the cached layouts are invalid and we
+ // should discard them; otherwise we will keep them and re-validate on the
+ // next layout pass.
+ void InvalidateLayout(bool force);
+
+ // Gets the proposed layout for a set of size bounds. Returns a cached layout
+ // if one is present and valid.
+ const Layout& CalculateLayout(const SizeBounds& bounds);
+
+ // Applies an existing layout to all child views, with the appropriate
+ // current alignment.
+ void DoLayout(const Layout& layout, const gfx::Rect& bounds);
+
+ private:
+ LayoutOrientation orientation() const { return layout_.orientation(); }
+
+ // Determines whether a layout is still valid.
+ bool IsLayoutValid(const Layout& cached_layout) const;
+
+ // Creates a brand new layout from the available |bounds|.
+ // Call DoLayout() to actually apply the layout.
+ const Layout& CalculateNewLayout(const NormalizedSizeBounds& bounds);
+
+ // Calculates the position of each child view and the size of the overall
+ // layout based on tentative visibilities and sizes for each child.
+ void UpdateLayoutFromChildren(Layout* layout,
+ ChildViewSpacing* child_spacing,
+ const NormalizedSizeBounds& bounds) const;
+
+ // Calculates a margin between two child views based on each's margin and any
+ // internal padding present in one or both elements. Uses properties of the
+ // layout, like whether adjacent margins should be collapsed.
+ int CalculateMargin(int margin1, int margin2, int internal_padding) const;
+
+ // Calculates the preferred spacing between two child views, or between a
+ // view edge and the first or last visible child views.
+ int CalculateChildSpacing(const Layout& layout,
+ base::Optional<int> child1_index,
+ base::Optional<int> child2_index) const;
+
+ const gfx::Insets& GetMargins(const View* view) const;
+
+ FlexLayout& layout_;
+
+ // Instead of marking each layout as dirty/needing validation, we instead keep
+ // a value that changes every time InvalidateLayout() is called. If the value
+ // stored in a cached layout doesn't match this value, we validate it and
+ // update the value. We use an int64_t because the odds of spurious collision
+ // (i.e. the counter wrapping back around to the *exact* same value before
+ // validating) are effectively zero.
+ uint32_t layout_counter_ = 0;
+ LayoutCache layout_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(FlexLayoutInternal);
+};
+
+void FlexLayoutInternal::InvalidateLayout(bool force) {
+ ++layout_counter_;
+ if (force)
+ layout_cache_.Clear();
+}
+
+const Layout& FlexLayoutInternal::CalculateLayout(const SizeBounds& bounds) {
+ // If bounds are smaller than the minimum cross axis size, expand them.
+ NormalizedSizeBounds normalized_bounds = Normalize(orientation(), bounds);
+ if (normalized_bounds.cross().has_value() &&
+ normalized_bounds.cross().value() < layout_.minimum_cross_axis_size()) {
+ normalized_bounds = NormalizedSizeBounds{normalized_bounds.main(),
+ layout_.minimum_cross_axis_size()};
+ }
+
+ // See if we have a cached layout already that is still valid.
+ Layout* const cached_layout = layout_cache_.Get(normalized_bounds);
+ if (cached_layout && IsLayoutValid(*cached_layout))
+ return *cached_layout;
+
+ // Calculate a new layout from scratch.
+ return CalculateNewLayout(normalized_bounds);
+}
+
+void FlexLayoutInternal::DoLayout(const Layout& layout,
+ const gfx::Rect& bounds) {
+ NormalizedPoint start = Normalize(orientation(), bounds.origin());
+
+ // Apply main axis alignment.
+ const int excess_main =
+ Normalize(orientation(), bounds.size()).main() - layout.total_size.main();
+ switch (layout_.main_axis_alignment()) {
+ case LayoutAlignment::kStart:
+ break;
+ case LayoutAlignment::kCenter:
+ start.set_main(start.main() + excess_main / 2);
+ break;
+ case LayoutAlignment::kEnd:
+ start.set_main(start.main() + excess_main);
+ break;
+ case LayoutAlignment::kStretch:
+ NOTIMPLEMENTED() << "Main axis stretch/justify is not yet supported.";
+ break;
+ }
+
+ // Position controls within the client area.
+ for (const ChildLayout& child_layout : layout.child_layouts) {
+ if (child_layout.excluded)
+ continue;
+ if (child_layout.visible != child_layout.view->visible())
+ layout_.SetViewVisibility(child_layout.view, child_layout.visible);
+ if (child_layout.visible) {
+ NormalizedRect actual = child_layout.actual_bounds;
+ actual.Offset(start.main(), start.cross());
+ gfx::Rect denormalized = Denormalize(orientation(), actual);
+ child_layout.view->SetBoundsRect(denormalized);
+ }
+ }
+}
+
+int FlexLayoutInternal::CalculateMargin(int margin1,
+ int margin2,
+ int internal_padding) const {
+ const int result = layout_.collapse_margins() ? std::max(margin1, margin2)
+ : margin1 + margin2;
+ return std::max(0, result - internal_padding);
+}
+
+int FlexLayoutInternal::CalculateChildSpacing(
+ const Layout& layout,
+ base::Optional<int> child1_index,
+ base::Optional<int> child2_index) const {
+ const int left_margin =
+ child1_index ? layout.child_layouts[*child1_index].margins.main_trailing()
+ : layout.interior_margin.main_leading();
+ const int right_margin =
+ child2_index ? layout.child_layouts[*child2_index].margins.main_leading()
+ : layout.interior_margin.main_trailing();
+ const int left_padding =
+ child1_index
+ ? layout.child_layouts[*child1_index].internal_padding.main_trailing()
+ : 0;
+ const int right_padding =
+ child2_index
+ ? layout.child_layouts[*child2_index].internal_padding.main_leading()
+ : 0;
+
+ return CalculateMargin(left_margin, right_margin,
+ left_padding + right_padding);
+}
+
+const gfx::Insets& FlexLayoutInternal::GetMargins(const View* view) const {
+ const gfx::Insets* const margins = view->GetProperty(views::kMarginsKey);
+ return margins ? *margins : layout_.default_child_margins();
+}
+
+void FlexLayoutInternal::UpdateLayoutFromChildren(
+ Layout* layout,
+ ChildViewSpacing* child_spacing,
+ const NormalizedSizeBounds& bounds) const {
+ // Calculate starting minimum for cross-axis size.
+ const int min_cross_size =
+ std::max(layout_.minimum_cross_axis_size(),
+ CalculateMargin(layout->interior_margin.cross_leading(),
+ layout->interior_margin.cross_trailing(), 0));
+ layout->total_size = NormalizedSize(0, min_cross_size);
+ if (bounds.cross().has_value())
+ layout->total_size.SetToMax(0, bounds.cross().value());
+
+ std::vector<Inset1D> cross_spacings(layout->child_layouts.size());
+ for (size_t i = 0; i < layout->child_layouts.size(); ++i) {
+ ChildLayout& child_layout = layout->child_layouts[i];
+
+ // We don't have to deal with excluded or invisible children.
+ if (child_layout.excluded || !child_layout.visible)
+ continue;
+
+ // Update the cross-axis size.
+ Inset1D& cross_spacing = cross_spacings[i];
+ cross_spacing.set_leading(
+ CalculateMargin(layout->interior_margin.cross_leading(),
+ child_layout.margins.cross_leading(),
+ child_layout.internal_padding.cross_leading()));
+ cross_spacing.set_trailing(
+ CalculateMargin(layout->interior_margin.cross_trailing(),
+ child_layout.margins.cross_trailing(),
+ child_layout.internal_padding.cross_trailing()));
+
+ const int cross_size = std::min(child_layout.current_size.cross(),
+ child_layout.preferred_size.cross());
+ layout->total_size.SetToMax(0, cross_spacing.size() + cross_size);
+
+ // Calculate main-axis size and upper-left main axis coordinate.
+ int leading_space;
+ if (child_spacing->HasViewIndex(i))
+ leading_space = child_spacing->GetLeadingSpace(i);
+ else
+ child_spacing->AddViewIndex(i, &leading_space);
+ layout->total_size.Enlarge(leading_space, 0);
+
+ const int size_main = child_layout.current_size.main();
+ child_layout.actual_bounds.set_origin_main(layout->total_size.main());
+ child_layout.actual_bounds.set_size_main(size_main);
+ layout->total_size.Enlarge(size_main, 0);
+ }
+
+ // Add the end margin.
+ layout->total_size.Enlarge(child_spacing->GetTrailingInset(), 0);
+
+ // Calculate vertical positioning given the cross-axis size we've already
+ // calculated above.
+ const Span cross_span(0, layout->total_size.cross());
+ for (size_t i = 0; i < layout->child_layouts.size(); ++i) {
+ ChildLayout& child_layout = layout->child_layouts[i];
+
+ // We don't have to deal with excluded or invisible children.
+ if (child_layout.excluded || !child_layout.visible)
+ continue;
+
+ // Because we have an explicit kStretch option, regardless of what the
+ // control *says* we won't allow the cross-axis size to exceed the preferred
+ // size. kStretch may cause it to become larger.
+ const int cross_size = std::min(child_layout.current_size.cross(),
+ child_layout.preferred_size.cross());
+ child_layout.actual_bounds.set_size_cross(cross_size);
+ child_layout.actual_bounds.AlignCross(
+ cross_span, layout_.cross_axis_alignment(), cross_spacings[i]);
+ }
+}
+
+const Layout& FlexLayoutInternal::CalculateNewLayout(
+ const NormalizedSizeBounds& bounds) {
+ DCHECK(!bounds.cross().has_value() ||
+ bounds.cross().value() >= layout_.minimum_cross_axis_size());
+ std::unique_ptr<Layout> layout = std::make_unique<Layout>(layout_counter_);
+ layout->interior_margin = Normalize(orientation(), layout_.interior_margin());
+ std::map<int, std::vector<int>> order_to_view_index;
+ const bool main_axis_bounded = bounds.main().has_value();
+
+ // Start with the smallest size the child view can occupy.
+ NormalizedSizeBounds effective_bounds{0, bounds.cross()};
+ if (effective_bounds.cross()) {
+ effective_bounds.set_cross(std::max(
+ 0, *effective_bounds.cross() - layout->interior_margin.cross_size()));
+ }
+
+ // Step through the children, creating placeholder layout view elements
+ // and setting up initial minimal visibility.
+ View* const view = layout_.host();
+ for (int i = 0; i < view->child_count(); ++i) {
+ View* child = view->child_at(i);
+ layout->child_layouts.emplace_back(child, layout_.GetFlexForView(child));
+ ChildLayout& child_layout = layout->child_layouts.back();
+
+ child_layout.excluded = layout_.IsViewExcluded(child);
+ if (child_layout.excluded)
+ continue;
+
+ child_layout.margins = Normalize(orientation(), GetMargins(child));
+ child_layout.internal_padding =
+ Normalize(orientation(), GetInternalPadding(child));
+ child_layout.preferred_size =
+ Normalize(orientation(), child->GetPreferredSize());
+
+ child_layout.hidden_by_owner = layout_.IsHiddenByOwner(child);
+ child_layout.visible = !child_layout.hidden_by_owner;
+ if (child_layout.hidden_by_owner)
+ continue;
+
+ // gfx::Size calculation depends on whether flex is allowed.
+ if (main_axis_bounded) {
+ child_layout.current_size =
+ Normalize(orientation(),
+ child_layout.flex.rule().Run(
+ child, Denormalize(orientation(), effective_bounds)));
+
+ // We should revisit whether this is a valid assumption for text views
+ // in vertical layouts.
+ DCHECK_GE(child_layout.preferred_size.main(),
+ child_layout.current_size.main());
+
+ // Keep track of non-hidden flex controls.
+ const bool can_flex =
+ (child_layout.flex.weight() > 0 &&
+ !child_layout.preferred_size.is_empty()) ||
+ child_layout.current_size.main() < child_layout.preferred_size.main();
+ if (can_flex)
+ order_to_view_index[child_layout.flex.order()].push_back(i);
+
+ } else {
+ // All non-flex or unbounded controls get preferred size.
+ child_layout.current_size = child_layout.preferred_size;
+ }
+
+ child_layout.visible = !child_layout.current_size.is_empty();
+
+ // Actual size and positioning will be set during the final layout
+ // calculation.
+ }
+
+ // Do the initial layout update, calculating spacing between children.
+ ChildViewSpacing child_spacing(
+ base::BindRepeating(&FlexLayoutInternal::CalculateChildSpacing,
+ base::Unretained(this), base::ConstRef(*layout)));
+ UpdateLayoutFromChildren(layout.get(), &child_spacing, bounds);
+
+ if (main_axis_bounded && !order_to_view_index.empty()) {
+ // Step through each flex priority allocating as much remaining space as
+ // possible to each flex view.
+ for (auto flex_it = order_to_view_index.begin();
+ flex_it != order_to_view_index.end(); ++flex_it) {
+ // Check to see we haven't filled available space.
+ int remaining = *bounds.main() - layout->total_size.main();
+ if (remaining <= 0) {
+ break;
+ }
+
+ // The flex algorithm we're using works as follows:
+ // * For each child view at a particular flex order:
+ // - Calculate the percentage of the remaining flex space to allocate
+ // based on the ratio of its weight to the total unallocated weight
+ // at that order.
+ // - If the child view is already visible (it will be at its minimum
+ // size, which may or may not be zero), add the space the child is
+ // already taking up.
+ // - If the child view is not visible and adding it would introduce
+ // additional margin space between child views, subtract that
+ // additional space from the amount available.
+ // - Ask the child view's flex rule how large it would like to be
+ // within the space available.
+ // - If the child view would like to be larger, make it so, and
+ // subtract the additional space consumed by the child and its
+ // margins from the total remaining flex space.
+ //
+ // Note that this algorithm isn't *perfect* for specific cases, which are
+ // noted below; namely when margins very asymmetrical the sizing of child
+ // views can be slightly different from what would otherwise be expected.
+ // We have a TODO to look at ways of making this algorithm more "fair" in
+ // the future (but in the meantime most issues can be resolved by setting
+ // reasonable margins and by using flex order).
+
+ // Build a list of the elements to flex.
+ int flex_total = 0;
+ std::for_each(flex_it->second.begin(), flex_it->second.end(),
+ [&](int index) {
+ auto weight = layout->child_layouts[index].flex.weight();
+ if (weight > 0)
+ flex_total += weight;
+ });
+
+ // Note: because the child views are evaluated in order, if preferred
+ // minimum sizes are not consistent across a single priority expanding
+ // the parent control could result in children swapping visibility.
+ // We currently consider this user error; if the behavior is not
+ // desired, prioritize the child views' flex.
+ for (auto index_it = flex_it->second.begin();
+ remaining >= 0 && index_it != flex_it->second.end(); ++index_it) {
+ const int view_index = *index_it;
+
+ ChildLayout& child_layout = layout->child_layouts[view_index];
+
+ // Offer a share of the remaining space to the view.
+ int flex_amount;
+ if (child_layout.flex.weight() > 0) {
+ const int flex_weight = child_layout.flex.weight();
+ // Round up so we give slightly greater weight to earlier views.
+ flex_amount =
+ int{std::ceil((float{remaining} * flex_weight) / flex_total)};
+ flex_total -= flex_weight;
+ } else {
+ flex_amount = remaining;
+ }
+
+ // If the layout was previously invisible, then making it visible
+ // may result in the addition of margin space, so we'll have to
+ // recalculate the margins on either side of this view. The change in
+ // margin space (if any) counts against the child view's flex space
+ // allocation.
+ //
+ // Note: In cases where the layout's internal margins and/or the child
+ // views' margins are wildly different sizes, subtracting the full delta
+ // out of the available space can cause the first view to be smaller
+ // than we would expect (see TODOs in unit tests for examples). We
+ // should look into ways to make this "feel" better (but in the
+ // meantime, please try to specify reasonable margins).
+ const int margin_delta = child_spacing.HasViewIndex(view_index)
+ ? 0
+ : child_spacing.GetAddDelta(view_index);
+
+ // This is the space on the main axis that was already allocated to the
+ // child view; it will be added to the total flex space for the child
+ // view since it is considered a fixed overhead of the layout if it is
+ // nonzero.
+ const int old_size =
+ child_layout.visible ? child_layout.current_size.main() : 0;
+
+ // Offer the modified flex space to the child view and see how large it
+ // wants to be (or if it wants to be visible at that size at all).
+ const NormalizedSizeBounds available(
+ flex_amount + old_size - margin_delta, effective_bounds.cross());
+ const NormalizedSize new_size = Normalize(
+ orientation(),
+ child_layout.flex.rule().Run(
+ child_layout.view, Denormalize(orientation(), available)));
+ if (new_size.is_empty())
+ continue;
+
+ // If the amount of space claimed increases (but is still within
+ // bounds set by our flex rule) we can make the control visible and
+ // claim the additional space.
+ const int to_deduct = (new_size.main() - old_size) + margin_delta;
+ DCHECK_GE(to_deduct, 0);
+ if (to_deduct > 0 && to_deduct <= remaining) {
+ child_layout.available_size = available;
+ child_layout.current_size = new_size;
+ child_layout.visible = true;
+ remaining -= to_deduct;
+ if (!child_spacing.HasViewIndex(view_index))
+ child_spacing.AddViewIndex(view_index);
+ }
+ }
+
+ // Reposition the child controls (taking margins into account) and
+ // calculate remaining space.
+ UpdateLayoutFromChildren(layout.get(), &child_spacing, bounds);
+ }
+ }
+
+ const Layout& result = *layout;
+ layout_cache_.Put(bounds, std::move(layout));
+ return result;
+}
+
+bool FlexLayoutInternal::IsLayoutValid(const Layout& cached_layout) const {
+ // If we've already evaluated a layout for this size and not been
+ // invalidated since then, then this is a valid layout.
+ if (cached_layout.layout_id == layout_counter_)
+ return true;
+
+ // Need to compare preferred child sizes with what we're seeing.
+ View* const view = layout_.host();
+ int child_index = 0;
+ for (const ChildLayout& proposed_view_layout : cached_layout.child_layouts) {
+ // Check that there is another child and that it's the view we expect.
+ DCHECK(child_index < view->child_count())
+ << "Child views should not be removed without clearing the cache.";
+
+ const View* child = view->child_at(child_index++);
+
+ // Ensure child views have not been reordered.
+ if (child != proposed_view_layout.view)
+ return false;
+
+ // Ignore hidden and excluded views, unless their status has changed.
+ const bool excluded = layout_.IsViewExcluded(child);
+ if (proposed_view_layout.excluded != excluded)
+ return false;
+ if (excluded)
+ continue;
+
+ const bool hidden_by_owner = layout_.IsHiddenByOwner(child);
+ if (proposed_view_layout.hidden_by_owner != hidden_by_owner)
+ return false;
+ if (hidden_by_owner)
+ continue;
+
+ // Sanity check that a child's visibility hasn't been modified outside
+ // the layout manager.
+ if (proposed_view_layout.visible != child->visible())
+ return false;
+
+ if (proposed_view_layout.visible) {
+ // Check that view margins haven't changed for visible controls.
+ if (GetMargins(child) !=
+ Denormalize(orientation(), proposed_view_layout.margins))
+ return false;
+
+ // Same for internal padding.
+ if (GetInternalPadding(child) !=
+ Denormalize(orientation(), proposed_view_layout.internal_padding))
+ return false;
+ }
+
+ // Check that the control still has the same preferred size given its
+ // flex and visibility.
+ if (child->GetPreferredSize() !=
+ Denormalize(orientation(), proposed_view_layout.preferred_size))
+ return false;
+
+ const gfx::Size preferred = proposed_view_layout.flex.rule().Run(
+ child, Denormalize(orientation(), proposed_view_layout.available_size));
+ if (preferred !=
+ Denormalize(orientation(), proposed_view_layout.current_size))
+ return false;
+ }
+
+ DCHECK_EQ(child_index, view->child_count()) << "Child views added without "
+ "clearing the cache - this "
+ "should not happen.";
+
+ // This layout is still valid. Update the layout counter to show it's valid
+ // in the current layout context.
+ cached_layout.layout_id = layout_counter_;
+ return true;
+}
+
+} // namespace internal
+
+// FlexLayout
+// -------------------------------------------------------------------
+
+FlexLayout::FlexLayout()
+ : internal_(std::make_unique<internal::FlexLayoutInternal>(this)) {}
+
+FlexLayout::~FlexLayout() {}
+
+FlexLayout& FlexLayout::SetOrientation(LayoutOrientation orientation) {
+ if (orientation != orientation_) {
+ orientation_ = orientation;
+ internal_->InvalidateLayout(true);
+ }
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetCollapseMargins(bool collapse_margins) {
+ if (collapse_margins != collapse_margins_) {
+ collapse_margins_ = collapse_margins;
+ internal_->InvalidateLayout(true);
+ }
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetMainAxisAlignment(
+ LayoutAlignment main_axis_alignment) {
+ DCHECK_NE(main_axis_alignment, LayoutAlignment::kStretch)
+ << "Main axis stretch/justify is not yet supported.";
+ if (main_axis_alignment_ != main_axis_alignment) {
+ main_axis_alignment_ = main_axis_alignment;
+ internal_->InvalidateLayout(true);
+ }
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetCrossAxisAlignment(
+ LayoutAlignment cross_axis_alignment) {
+ if (cross_axis_alignment_ != cross_axis_alignment) {
+ cross_axis_alignment_ = cross_axis_alignment;
+ internal_->InvalidateLayout(true);
+ }
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetInteriorMargin(const gfx::Insets& interior_margin) {
+ if (interior_margin_ != interior_margin) {
+ interior_margin_ = interior_margin;
+ internal_->InvalidateLayout(true);
+ }
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetMinimumCrossAxisSize(int size) {
+ if (minimum_cross_axis_size_ != size) {
+ minimum_cross_axis_size_ = size;
+ internal_->InvalidateLayout(true);
+ }
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetDefaultChildMargins(const gfx::Insets& margins) {
+ if (default_child_margins_ != margins) {
+ default_child_margins_ = margins;
+ internal_->InvalidateLayout(true);
+ }
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetFlexForView(
+ const View* view,
+ const FlexSpecification& flex_specification) {
+ auto it = child_params_.find(view);
+ DCHECK(it != child_params_.end());
+ it->second.flex_specification = flex_specification;
+ internal_->InvalidateLayout(true);
+ return *this;
+}
+
+FlexLayout& FlexLayout::ClearFlexForView(const View* view) {
+ auto it = child_params_.find(view);
+ DCHECK(it != child_params_.end());
+ it->second.flex_specification.reset();
+ internal_->InvalidateLayout(true);
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetViewExcluded(const View* view, bool excluded) {
+ auto it = child_params_.find(view);
+ DCHECK(it != child_params_.end());
+ if (excluded != it->second.excluded) {
+ it->second.excluded = excluded;
+ InvalidateLayout();
+ }
+ return *this;
+}
+
+FlexLayout& FlexLayout::SetDefaultFlex(
+ const FlexSpecification& flex_specification) {
+ default_flex_ = flex_specification;
+ internal_->InvalidateLayout(true);
+ return *this;
+}
+
+const FlexSpecification& FlexLayout::GetFlexForView(const View* view) const {
+ auto it = child_params_.find(view);
+ DCHECK(it != child_params_.end());
+ const base::Optional<FlexSpecification>& spec = it->second.flex_specification;
+ return spec ? *spec : default_flex_;
+}
+
+bool FlexLayout::IsViewExcluded(const View* view) const {
+ auto it = child_params_.find(view);
+ DCHECK(it != child_params_.end());
+ return it->second.excluded;
+}
+
+bool FlexLayout::IsHiddenByOwner(const View* view) const {
+ auto it = child_params_.find(view);
+ DCHECK(it != child_params_.end());
+ return it->second.hidden_by_owner;
+}
+
+gfx::Size FlexLayout::GetPreferredSize(const View* host) const {
+ DCHECK_EQ(host_, host);
+ return GetPreferredSize(SizeBounds());
+}
+
+int FlexLayout::GetPreferredHeightForWidth(const View* host, int width) const {
+ DCHECK_EQ(host_, host);
+ return GetPreferredSize(SizeBounds{width, base::Optional<int>()}).height();
+}
+
+gfx::Size FlexLayout::GetMinimumSize(const View* host) const {
+ DCHECK_EQ(host_, host);
+ return GetPreferredSize(SizeBounds{0, 0});
+}
+
+void FlexLayout::InvalidateLayout() {
+ internal_->InvalidateLayout(false);
+}
+
+void FlexLayout::Installed(View* host) {
+ DCHECK(!host_);
+ host_ = host;
+ // Add all the existing children when the layout manager is installed.
+ // If new children are added, ViewAdded() will be called and we'll add data
+ // there.
+ for (int i = 0; i < host->child_count(); ++i) {
+ View* const child = host->child_at(i);
+ internal::ChildLayoutParams child_layout_params;
+ child_layout_params.hidden_by_owner = !child->visible();
+ child_params_.emplace(child, child_layout_params);
+ }
+}
+
+void FlexLayout::ViewAdded(View* host, View* view) {
+ DCHECK_EQ(host_, host);
+ internal::ChildLayoutParams child_layout_params;
+ child_layout_params.hidden_by_owner = !view->visible();
+ child_params_.emplace(view, child_layout_params);
+ internal_->InvalidateLayout(true);
+}
+
+void FlexLayout::ViewRemoved(View* host, View* view) {
+ child_params_.erase(view);
+ internal_->InvalidateLayout(true);
+}
+
+void FlexLayout::ViewVisibilitySet(View* host, View* view, bool visible) {
+ DCHECK_EQ(host, host_);
+ DCHECK_EQ(view->parent(), host);
+ auto it = child_params_.find(view);
+ DCHECK(it != child_params_.end());
+ const bool hide = !visible;
+ if (it->second.hidden_by_owner != hide) {
+ it->second.hidden_by_owner = hide;
+ if (!it->second.excluded) {
+ // It's not always obvious to our host that an owner of a child view
+ // changing its visibility could change a layout. So we'll notify the host
+ // view that its layout is potentially invalid, and it will in turn call
+ // InvalidateLayout() on the layout manager (i.e. this object).
+ host_->InvalidateLayout();
+ }
+ }
+}
+
+// Retrieve the preferred size for the control in the given bounds.
+gfx::Size FlexLayout::GetPreferredSize(const SizeBounds& bounds) const {
+ if (!host_)
+ return gfx::Size();
+
+ const gfx::Insets insets = host_->GetInsets();
+ SizeBounds content_bounds = bounds;
+ content_bounds.Enlarge(-insets.width(), -insets.height());
+ const internal::Layout& proposed_layout =
+ internal_->CalculateLayout(content_bounds);
+ gfx::Size result = Denormalize(orientation(), proposed_layout.total_size);
+ result.Enlarge(insets.width(), insets.height());
+ return result;
+}
+
+void FlexLayout::Layout(View* host) {
+ DCHECK_EQ(host, host_);
+ // TODO(dfried): for a handful of views which override GetInsets(), the way
+ // this method is implemented in View may be incorrect. Please revisit.
+ gfx::Rect bounds = host_->GetContentsBounds();
+ const internal::Layout& layout =
+ internal_->CalculateLayout(SizeBounds(bounds.size()));
+
+ internal_->DoLayout(layout, bounds);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/layout/flex_layout.h b/chromium/ui/views/layout/flex_layout.h
new file mode 100644
index 00000000000..45c518133f0
--- /dev/null
+++ b/chromium/ui/views/layout/flex_layout.h
@@ -0,0 +1,174 @@
+// 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_LAYOUT_FLEX_LAYOUT_H_
+#define UI_VIEWS_LAYOUT_FLEX_LAYOUT_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/views/layout/flex_layout_types.h"
+#include "ui/views/layout/layout_manager.h"
+
+namespace gfx {
+class Size;
+} // namespace gfx
+
+namespace views {
+
+namespace internal {
+struct ChildLayoutParams;
+class FlexLayoutInternal;
+} // namespace internal
+
+class View;
+
+// Provides CSS-like layout for a one-dimensional (vertical or horizontal)
+// arrangement of child views. Independent alignment can be specified for the
+// main and cross axes.
+//
+// Per-View margins (provided by view property kMarginsKey) specify how much
+// space to leave around each child view. The |interior_margin| says how much
+// empty space to leave at the edges of the parent view. If |collapse_margins|
+// is false, these values are additive; if true, the greater of the two values
+// is used. The |default_child_margins| provides a fallback for views without
+// kMarginsKey set.
+//
+// collapse_margins = false:
+//
+// | interior margin> <margin [view]...
+// | <margin [view] margin>
+//
+// collapse_margins = true:
+//
+// | interior margin> <margin [view]
+// | <margin [view] margin> ...
+//
+// Views can have their own internal padding, using the kInternalPaddingKey
+// property, which is subtracted from the margin space between child views.
+//
+// Calling SetVisible(false) on a child view outside of the FlexLayout will
+// result in the child view being hidden until SetVisible(true) is called. This
+// is irrespective of whether the FlexLayout has set the child view to be
+// visible or not based on, for example, flex rules.
+//
+// If you want the host view to maintain control over a child view, you can
+// exclude it from the layout. Excluded views are completely ignored during
+// layout and do not have their properties modified.
+//
+// FlexSpecification objects determine how child views are sized. You can set
+// individual flex rules for each child view, or a default for any child views
+// without individual flex rules set. If you don't set anything, each view will
+// take up its preferred size in the layout.
+//
+// The core function of this class is contained in
+// GetPreferredSize(maximum_size) and Layout(host). In both cases, a layout will
+// be cached and typically not recalculated as long as none of the layout's
+// properties or the preferred size or visibility of any of its children has
+// changed.
+class VIEWS_EXPORT FlexLayout : public LayoutManager {
+ public:
+ FlexLayout();
+ ~FlexLayout() override;
+
+ // Note: setters provide a Builder-style interface, so you can type:
+ // layout.SetMainAxisAlignment()
+ // .SetCrossAxisAlignment()
+ // .SetDefaultFlex(...);
+ FlexLayout& SetOrientation(LayoutOrientation orientation);
+ FlexLayout& SetCollapseMargins(bool collapse_margins);
+ FlexLayout& SetMainAxisAlignment(LayoutAlignment main_axis_alignment);
+ FlexLayout& SetCrossAxisAlignment(LayoutAlignment cross_axis_alignment);
+ FlexLayout& SetInteriorMargin(const gfx::Insets& interior_margin);
+ FlexLayout& SetMinimumCrossAxisSize(int size);
+ FlexLayout& SetDefaultChildMargins(const gfx::Insets& margins);
+ FlexLayout& SetFlexForView(const View* view,
+ const FlexSpecification& flex_specification);
+ FlexLayout& ClearFlexForView(const View* view);
+ FlexLayout& SetDefaultFlex(const FlexSpecification& flex_specification);
+
+ // Set whether a view should be excluded from the layout. Excluded views will
+ // be completely ignored and must be explicitly placed by the host view.
+ FlexLayout& SetViewExcluded(const View* view, bool excluded);
+
+ View* host() { return host_; }
+ const View* host() const { return host_; }
+ LayoutOrientation orientation() const { return orientation_; }
+ bool collapse_margins() const { return collapse_margins_; }
+ LayoutAlignment main_axis_alignment() const { return main_axis_alignment_; }
+ LayoutAlignment cross_axis_alignment() const { return cross_axis_alignment_; }
+ const gfx::Insets& interior_margin() const { return interior_margin_; }
+ int minimum_cross_axis_size() const { return minimum_cross_axis_size_; }
+ const gfx::Insets& default_child_margins() const {
+ return default_child_margins_;
+ }
+ const FlexSpecification& default_flex() const { return default_flex_; }
+
+ const FlexSpecification& GetFlexForView(const View* view) const;
+ bool IsViewExcluded(const View* view) const;
+ bool IsHiddenByOwner(const View* view) const;
+
+ // Retrieve the preferred size for the control in the given bounds.
+ gfx::Size GetPreferredSize(const SizeBounds& maximum_size) const;
+
+ protected:
+ // views::LayoutManager:
+ void Installed(View* host) override;
+ void InvalidateLayout() override;
+ void ViewAdded(View* host, View* view) override;
+ void ViewRemoved(View* host, View* view) override;
+ void ViewVisibilitySet(View* host, View* view, bool visible) override;
+ void Layout(View* host) override;
+ gfx::Size GetPreferredSize(const View* host) const override;
+ gfx::Size GetMinimumSize(const View* host) const override;
+ int GetPreferredHeightForWidth(const View* host, int width) const override;
+
+ private:
+ friend class internal::FlexLayoutInternal;
+
+ LayoutOrientation orientation_ = LayoutOrientation::kHorizontal;
+
+ // Adjacent view margins should be collapsed.
+ bool collapse_margins_ = false;
+
+ // Spacing between child views and host view border.
+ gfx::Insets interior_margin_;
+
+ // Default spacing to put around child views.
+ gfx::Insets default_child_margins_;
+
+ // Child-view-specific details (e.g. hidden status, flex rules, etc.)
+ std::map<const View*, internal::ChildLayoutParams> child_params_;
+
+ // The alignment of children in the main axis. This is start by default.
+ LayoutAlignment main_axis_alignment_ = LayoutAlignment::kStart;
+
+ // The alignment of children in the cross axis. This is stretch by default.
+ LayoutAlignment cross_axis_alignment_ = LayoutAlignment::kStretch;
+
+ // The minimum cross axis size for the layout.
+ int minimum_cross_axis_size_ = 0;
+
+ // Flex specification for components with no flex set.
+ FlexSpecification default_flex_;
+
+ // The view that this FlexLayout is managing the layout for.
+ views::View* host_ = nullptr;
+
+ // Internal data used to cache layout information, etc. All definitions and
+ // data are module-private.
+ std::unique_ptr<internal::FlexLayoutInternal> internal_;
+
+ DISALLOW_COPY_AND_ASSIGN(FlexLayout);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_LAYOUT_FLEX_LAYOUT_H_
diff --git a/chromium/ui/views/layout/flex_layout_types.cc b/chromium/ui/views/layout/flex_layout_types.cc
new file mode 100644
index 00000000000..692e7262758
--- /dev/null
+++ b/chromium/ui/views/layout/flex_layout_types.cc
@@ -0,0 +1,203 @@
+// 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/layout/flex_layout_types.h"
+
+#include <algorithm>
+#include <tuple>
+
+#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/view.h"
+
+namespace views {
+
+namespace {
+
+std::string OptionalToString(const base::Optional<int>& opt) {
+ if (!opt.has_value())
+ return "_";
+ return base::StringPrintf("%d", opt.value());
+}
+
+// Default Flex Rules ----------------------------------------------------------
+
+// Interpolates a size between minimum, preferred size, and upper bound based on
+// sizing rules, returning the resulting ideal size.
+int InterpolateSize(MinimumFlexSizeRule minimum_size_rule,
+ MaximumFlexSizeRule maximum_size_rule,
+ int minimum_size,
+ int preferred_size,
+ int available_size) {
+ if (available_size < minimum_size) {
+ switch (minimum_size_rule) {
+ case MinimumFlexSizeRule::kScaleToZero:
+ return available_size;
+ case MinimumFlexSizeRule::kPreferred:
+ return preferred_size;
+ case MinimumFlexSizeRule::kScaleToMinimum:
+ case MinimumFlexSizeRule::kPreferredSnapToMinimum:
+ return minimum_size;
+ case MinimumFlexSizeRule::kScaleToMinimumSnapToZero:
+ case MinimumFlexSizeRule::kPreferredSnapToZero:
+ return 0;
+ }
+ } else if (available_size < preferred_size) {
+ switch (minimum_size_rule) {
+ case MinimumFlexSizeRule::kPreferred:
+ return preferred_size;
+ case MinimumFlexSizeRule::kScaleToZero:
+ case MinimumFlexSizeRule::kScaleToMinimum:
+ case MinimumFlexSizeRule::kScaleToMinimumSnapToZero:
+ return available_size;
+ case MinimumFlexSizeRule::kPreferredSnapToMinimum:
+ return minimum_size;
+ case MinimumFlexSizeRule::kPreferredSnapToZero:
+ return 0;
+ }
+ } else {
+ switch (maximum_size_rule) {
+ case MaximumFlexSizeRule::kPreferred:
+ return preferred_size;
+ case MaximumFlexSizeRule::kUnbounded:
+ return available_size;
+ }
+ }
+}
+
+gfx::Size GetPreferredSize(MinimumFlexSizeRule minimum_size_rule,
+ MaximumFlexSizeRule maximum_size_rule,
+ const views::View* view,
+ const views::SizeBounds& maximum_size) {
+ gfx::Size min = view->GetMinimumSize();
+ gfx::Size preferred = view->GetPreferredSize();
+
+ int width, height;
+
+ if (!maximum_size.width()) {
+ // Not having a maximum size is different from having a large available
+ // size; a view can't grow infinitely, so we go with its preferred size.
+ width = preferred.width();
+ } else {
+ width = InterpolateSize(minimum_size_rule, maximum_size_rule, min.width(),
+ preferred.width(), *maximum_size.width());
+ }
+
+ // Allow views that need to grow vertically when they're compressed
+ // horizontally to do so.
+ //
+ // If we just went with GetHeightForWidth() we would have situations where an
+ // empty text control wanted no (or very little) height which could cause a
+ // layout to shrink vertically; we will always try to allocate at least the
+ // view's reported preferred height.
+ //
+ // Note that this is an adjustment made for practical considerations, and may
+ // not be "correct" in some absolute sense. Let's revisit at some point.
+ const int preferred_height =
+ std::max(preferred.height(), view->GetHeightForWidth(width));
+
+ if (!maximum_size.height()) {
+ // Not having a maximum size is different from having a large available
+ // size; a view can't grow infinitely, so we go with its preferred size.
+ height = preferred_height;
+ } else {
+ height = InterpolateSize(minimum_size_rule, maximum_size_rule, min.height(),
+ preferred_height, *maximum_size.height());
+ }
+
+ return gfx::Size(width, height);
+}
+
+FlexRule GetDefaultFlexRule(
+ MinimumFlexSizeRule minimum_size_rule = MinimumFlexSizeRule::kPreferred,
+ MaximumFlexSizeRule maximum_size_rule = MaximumFlexSizeRule::kPreferred) {
+ return base::BindRepeating(&GetPreferredSize, minimum_size_rule,
+ maximum_size_rule);
+}
+
+} // namespace
+
+// SizeBounds ------------------------------------------------------------------
+
+SizeBounds::SizeBounds() = default;
+
+SizeBounds::SizeBounds(const base::Optional<int>& width,
+ const base::Optional<int>& height)
+ : width_(width), height_(height) {}
+
+SizeBounds::SizeBounds(const SizeBounds& other)
+ : width_(other.width()), height_(other.height()) {}
+
+SizeBounds::SizeBounds(const gfx::Size& other)
+ : width_(other.width()), height_(other.height()) {}
+
+void SizeBounds::Enlarge(int width, int height) {
+ if (width_)
+ width_ = std::max(0, *width_ + width);
+ if (height_)
+ height_ = std::max(0, *height_ + height);
+}
+
+bool SizeBounds::operator==(const SizeBounds& other) const {
+ return width_ == other.width_ && height_ == other.height_;
+}
+
+bool SizeBounds::operator!=(const SizeBounds& other) const {
+ return !(*this == other);
+}
+
+bool SizeBounds::operator<(const SizeBounds& other) const {
+ return std::tie(height_, width_) < std::tie(other.height_, other.width_);
+}
+
+std::string SizeBounds::ToString() const {
+ return base::StringPrintf("%s x %s", OptionalToString(width()).c_str(),
+ OptionalToString(height()).c_str());
+}
+
+// FlexSpecification -----------------------------------------------------------
+
+FlexSpecification::FlexSpecification()
+ : rule_(GetDefaultFlexRule()), order_(1), weight_(0) {}
+
+FlexSpecification FlexSpecification::ForCustomRule(const FlexRule& rule) {
+ return FlexSpecification(rule, 1, 1);
+}
+
+FlexSpecification FlexSpecification::ForSizeRule(
+ MinimumFlexSizeRule minimum_size_rule,
+ MaximumFlexSizeRule maximum_size_rule) {
+ return FlexSpecification(
+ GetDefaultFlexRule(minimum_size_rule, maximum_size_rule), 1, 1);
+}
+
+FlexSpecification::FlexSpecification(const FlexRule& rule,
+ int order,
+ int weight)
+ : rule_(rule), order_(order), weight_(weight) {}
+
+FlexSpecification::FlexSpecification(const FlexSpecification& other)
+ : rule_(other.rule_), order_(other.order_), weight_(other.weight_) {}
+
+FlexSpecification& FlexSpecification::operator=(
+ const FlexSpecification& other) {
+ rule_ = other.rule_;
+ order_ = other.order_;
+ weight_ = other.weight_;
+ return *this;
+}
+
+FlexSpecification::~FlexSpecification() = default;
+
+FlexSpecification FlexSpecification::WithWeight(int weight) const {
+ DCHECK_GE(weight, 0);
+ return FlexSpecification(rule_, order_, weight);
+}
+
+FlexSpecification FlexSpecification::WithOrder(int order) const {
+ DCHECK_GE(order, 1);
+ return FlexSpecification(rule_, order, weight_);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/layout/flex_layout_types.h b/chromium/ui/views/layout/flex_layout_types.h
new file mode 100644
index 00000000000..2813d30d33f
--- /dev/null
+++ b/chromium/ui/views/layout/flex_layout_types.h
@@ -0,0 +1,164 @@
+// 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_LAYOUT_FLEX_LAYOUT_TYPES_H_
+#define UI_VIEWS_LAYOUT_FLEX_LAYOUT_TYPES_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/optional.h"
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace views {
+
+class View;
+
+// Whether a layout is oriented horizontally or vertically.
+enum class LayoutOrientation {
+ kHorizontal,
+ kVertical,
+};
+
+// Describes how elements should be aligned within a layout.
+enum class LayoutAlignment { kStart, kCenter, kEnd, kStretch };
+
+// Stores an optional width and height upper bound. Used when calculating the
+// preferred size of a layout pursuant to a maximum available size.
+class VIEWS_EXPORT SizeBounds {
+ public:
+ SizeBounds();
+ SizeBounds(const base::Optional<int>& width,
+ const base::Optional<int>& height);
+ explicit SizeBounds(const gfx::Size& size);
+ SizeBounds(const SizeBounds& other);
+
+ const base::Optional<int>& width() const { return width_; }
+ void set_width(const base::Optional<int>& width) { width_ = width; }
+
+ const base::Optional<int>& height() const { return height_; }
+ void set_height(const base::Optional<int>& height) { height_ = height; }
+
+ // Enlarges (or shrinks, if negative) each upper bound that is present by the
+ // specified amounts.
+ void Enlarge(int width, int height);
+
+ bool operator==(const SizeBounds& other) const;
+ bool operator!=(const SizeBounds& other) const;
+ bool operator<(const SizeBounds& other) const;
+
+ std::string ToString() const;
+
+ private:
+ base::Optional<int> width_;
+ base::Optional<int> height_;
+};
+
+// Callback used to specify the size of a child view based on its size bounds.
+// Create your own custom rules, or use the Minimum|MaximumFlexSizeRule
+// constants below for common behaviors.
+//
+// This callback takes two parameters: a child view, and a set of size bounds
+// representing the available space for that child view to occupy. The function
+// returns the preferred size of the view within those bounds, which may exceed
+// them if the child is not capable of shrinking to the specified size. The
+// callback may also return an empty size, which means the child view can drop
+// out of the layout. Not specifying either bound means there is an unlimited
+// amount of room for the child view in that dimension (and the child view
+// should probably use its preferred size).
+//
+// We provide the ability to use an arbitrary function here because some views
+// have complex sizing behavior; for example, they may shrink stepwise as their
+// internal elements drop out due to lack of space.
+using FlexRule =
+ base::RepeatingCallback<gfx::Size(const View*, const SizeBounds&)>;
+
+// Describes a simple rule for how a child view should shrink in a layout when
+// the available size for that view decreases.
+enum class MinimumFlexSizeRule {
+ kScaleToZero, // Ignore minimum size and scale all the way down.
+ kScaleToMinimumSnapToZero, // Scale to minimum then snap to zero.
+ kPreferredSnapToZero, // Use preferred, then snap to zero.
+ kScaleToMinimum, // Resize down to minimum then stop.
+ kPreferredSnapToMinimum, // Use preferred, then snap to minimum.
+ kPreferred // Always use preferred size.
+};
+
+// Describes a simple rule for how a child view should grow in a layout when
+// there is extra size avaialble for that view to occupy.
+enum MaximumFlexSizeRule {
+ kPreferred, // Don't resize above preferred size.
+ kUnbounded // Allow resize to arbitrary size.
+};
+
+// Specifies how a view should flex (i.e. grow or shrink) within its parent as
+// the available space changes. Flex specifications have three components:
+// - A |rule| which tells the layout manager how the child view resizes with
+// available space.
+// - A |weight| which specifies how much of the available space is allocated to
+// a child view that can flex. The percentage of space allocated is the
+// weight divided by the total weight of all views at this order (see below).
+// - An |order| which specifies the priority with which available space is
+// allocated. All available space is offered to child views at order 1, then
+// any remaining space is offered to order 2, and so forth.
+//
+// For example, say there are three child controls in a horizontal layout, each
+// of which has a flex rule that allows it to be between 0 and 20 DIPs wide.
+// Child A is at order 2 with weight 2, child B is at order 1 with weight 1, and
+// child C is at order 2 and weight 1. The parent control is 50 DIPs across and
+// has no margins.
+//
+// All 50 DIPs are offered to child B, since it is first in order. It consumes
+// 20 DIPs, its maximum size. Of the remaining 30, 20 are offered to child A and
+// 10 are offered to child C, each of which they take - the 2:1 ratio is due to
+// the different weights. (Also note that, if there were another child at order
+// 3, it would be offered zero DIPs and might choose not to display itself.)
+class VIEWS_EXPORT FlexSpecification {
+ public:
+ // Creates a flex specification with the default rule (no flex, always use the
+ // view's preferred size).
+ FlexSpecification();
+
+ FlexSpecification(const FlexSpecification& other);
+ FlexSpecification& operator=(const FlexSpecification& other);
+
+ ~FlexSpecification();
+
+ // Creates a flex specification with a custom flex rule. Note that any copies
+ // or mutations of this specification will also inherit the rule.
+ static FlexSpecification ForCustomRule(const FlexRule& rule);
+
+ // Creates a flex specification using the specififed minimum size and size
+ // bounds rules.
+ static FlexSpecification ForSizeRule(MinimumFlexSizeRule minimum_size_rule,
+ MaximumFlexSizeRule maximum_size_rule);
+
+ // Makes a copy of this specification with a different order.
+ FlexSpecification WithOrder(int order) const;
+
+ // Makes a copy of this specification with a different weight.
+ // Specifying |weight| of zero means the view will take as much space as it
+ // needs.
+ FlexSpecification WithWeight(int weight) const;
+
+ const FlexRule& rule() const { return rule_; }
+ int weight() const { return weight_; }
+ int order() const { return order_; }
+
+ private:
+ FlexSpecification(const FlexRule& rule, int order, int weight);
+
+ FlexRule rule_;
+ int order_;
+ int weight_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_LAYOUT_FLEX_LAYOUT_TYPES_H_
diff --git a/chromium/ui/views/layout/flex_layout_types_internal.cc b/chromium/ui/views/layout/flex_layout_types_internal.cc
new file mode 100644
index 00000000000..83e255ee27f
--- /dev/null
+++ b/chromium/ui/views/layout/flex_layout_types_internal.cc
@@ -0,0 +1,465 @@
+// 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/layout/flex_layout_types_internal.h"
+
+#include <algorithm>
+#include <tuple>
+
+#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/layout/flex_layout_types.h"
+
+namespace views {
+namespace internal {
+
+namespace {
+
+std::string OptionalToString(const base::Optional<int>& opt) {
+ if (!opt.has_value())
+ return "_";
+ return base::StringPrintf("%d", opt.value());
+}
+
+} // namespace
+
+// Span ------------------------------------------------------------------------
+
+void Span::SetSpan(int start, int length) {
+ start_ = start;
+ length_ = std::max(0, length);
+}
+
+void Span::Expand(int leading, int trailing) {
+ const int end = this->end();
+ set_start(start_ - leading);
+ set_end(end + trailing);
+}
+
+void Span::Inset(int leading, int trailing) {
+ Expand(-leading, -trailing);
+}
+
+void Span::Inset(const Inset1D& insets) {
+ Inset(insets.leading(), insets.trailing());
+}
+
+void Span::Center(const Span& container, const Inset1D& margins) {
+ const int margin_total = margins.size();
+ const int remaining = container.length() - (length() + margin_total);
+ if (remaining >= 0 || margin_total <= 0)
+ set_start(container.start() + margins.leading() + remaining / 2);
+ else
+ set_start(((container.length() - length()) * margins.leading()) /
+ margin_total);
+}
+
+void Span::Align(const Span& container,
+ LayoutAlignment alignment,
+ const Inset1D& margins) {
+ switch (alignment) {
+ case LayoutAlignment::kStart:
+ set_start(container.start() + margins.leading());
+ break;
+ case LayoutAlignment::kEnd:
+ set_start(container.end() - (margins.trailing() + length()));
+ break;
+ case LayoutAlignment::kCenter:
+ Center(container, margins);
+ break;
+ case LayoutAlignment::kStretch:
+ SetSpan(container.start() + margins.leading(),
+ std::max(0, container.length() - margins.size()));
+ break;
+ }
+}
+
+bool Span::operator==(const Span& other) const {
+ return start_ == other.start_ && length_ == other.length_;
+}
+
+bool Span::operator!=(const Span& other) const {
+ return !(*this == other);
+}
+
+bool Span::operator<(const Span& other) const {
+ return std::tie(start_, length_) < std::tie(other.start_, other.length_);
+}
+
+std::string Span::ToString() const {
+ return base::StringPrintf("%d [%d]", start(), length());
+}
+
+// Inset1D ---------------------------------------------------------------------
+
+void Inset1D::SetInsets(int leading, int trailing) {
+ leading_ = leading;
+ trailing_ = trailing;
+}
+
+void Inset1D::Expand(int delta_leading, int delta_trailing) {
+ leading_ += delta_leading;
+ trailing_ += delta_trailing;
+}
+
+bool Inset1D::operator==(const Inset1D& other) const {
+ return leading_ == other.leading_ && trailing_ == other.trailing_;
+}
+
+bool Inset1D::operator!=(const Inset1D& other) const {
+ return !(*this == other);
+}
+
+bool Inset1D::operator<(const Inset1D& other) const {
+ return std::tie(leading_, trailing_) <
+ std::tie(other.leading_, other.trailing_);
+}
+
+std::string Inset1D::ToString() const {
+ return base::StringPrintf("%d, %d", leading(), trailing());
+}
+
+// NormalizedPoint -------------------------------------------------------------
+
+void NormalizedPoint::SetPoint(int main, int cross) {
+ main_ = main;
+ cross_ = cross;
+}
+
+void NormalizedPoint::Offset(int delta_main, int delta_cross) {
+ main_ += delta_main;
+ cross_ += delta_cross;
+}
+
+bool NormalizedPoint::operator==(const NormalizedPoint& other) const {
+ return main_ == other.main_ && cross_ == other.cross_;
+}
+
+bool NormalizedPoint::operator!=(const NormalizedPoint& other) const {
+ return !(*this == other);
+}
+
+bool NormalizedPoint::operator<(const NormalizedPoint& other) const {
+ return std::tie(main_, cross_) < std::tie(other.main_, other.cross_);
+}
+
+std::string NormalizedPoint::ToString() const {
+ return base::StringPrintf("%d, %d", main(), cross());
+}
+
+// NormalizedSize --------------------------------------------------------------
+
+void NormalizedSize::SetSize(int main, int cross) {
+ main_ = std::max(0, main);
+ cross_ = std::max(0, cross);
+}
+
+void NormalizedSize::Enlarge(int delta_main, int delta_cross) {
+ main_ = std::max(0, main_ + delta_main);
+ cross_ = std::max(0, cross_ + delta_cross);
+}
+
+void NormalizedSize::SetToMax(int main, int cross) {
+ main_ = std::max(main_, main);
+ cross_ = std::max(cross_, cross);
+}
+
+void NormalizedSize::SetToMin(int main, int cross) {
+ main_ = std::max(0, std::min(main_, main));
+ cross_ = std::max(0, std::min(cross_, cross));
+}
+
+void NormalizedSize::SetToMax(const NormalizedSize& other) {
+ SetToMax(other.main(), other.cross());
+}
+
+void NormalizedSize::SetToMin(const NormalizedSize& other) {
+ SetToMin(other.main(), other.cross());
+}
+
+bool NormalizedSize::operator==(const NormalizedSize& other) const {
+ return main_ == other.main_ && cross_ == other.cross_;
+}
+
+bool NormalizedSize::operator!=(const NormalizedSize& other) const {
+ return !(*this == other);
+}
+
+bool NormalizedSize::operator<(const NormalizedSize& other) const {
+ return std::tie(main_, cross_) < std::tie(other.main_, other.cross_);
+}
+
+std::string NormalizedSize::ToString() const {
+ return base::StringPrintf("%d x %d", main(), cross());
+}
+
+// NormalizedInsets ------------------------------------------------------------
+
+bool NormalizedInsets::operator==(const NormalizedInsets& other) const {
+ return main_ == other.main_ && cross_ == other.cross_;
+}
+
+bool NormalizedInsets::operator!=(const NormalizedInsets& other) const {
+ return !(*this == other);
+}
+
+bool NormalizedInsets::operator<(const NormalizedInsets& other) const {
+ return std::tie(main_, cross_) < std::tie(other.main_, other.cross_);
+}
+
+std::string NormalizedInsets::ToString() const {
+ return base::StringPrintf("main: [%s], cross: [%s]",
+ main().ToString().c_str(),
+ cross().ToString().c_str());
+}
+
+// NormalizedSizeBounds --------------------------------------------------------
+
+NormalizedSizeBounds::NormalizedSizeBounds() = default;
+
+NormalizedSizeBounds::NormalizedSizeBounds(const base::Optional<int>& main,
+ const base::Optional<int>& cross)
+ : main_(main), cross_(cross) {}
+
+NormalizedSizeBounds::NormalizedSizeBounds(const NormalizedSizeBounds& other)
+ : main_(other.main()), cross_(other.cross()) {}
+
+NormalizedSizeBounds::NormalizedSizeBounds(const NormalizedSize& other)
+ : main_(other.main()), cross_(other.cross()) {}
+
+void NormalizedSizeBounds::Expand(int main, int cross) {
+ if (main_)
+ main_ = std::max(0, *main_ + main);
+ if (cross_)
+ cross_ = std::max(0, *cross_ + cross);
+}
+
+bool NormalizedSizeBounds::operator==(const NormalizedSizeBounds& other) const {
+ return main_ == other.main_ && cross_ == other.cross_;
+}
+
+bool NormalizedSizeBounds::operator!=(const NormalizedSizeBounds& other) const {
+ return !(*this == other);
+}
+
+bool NormalizedSizeBounds::operator<(const NormalizedSizeBounds& other) const {
+ return std::tie(main_, cross_) < std::tie(other.main_, other.cross_);
+}
+
+std::string NormalizedSizeBounds::ToString() const {
+ return base::StringPrintf("%s x %s", OptionalToString(main()).c_str(),
+ OptionalToString(cross()).c_str());
+}
+
+// NormalizedRect --------------------------------------------------------------
+
+Span NormalizedRect::GetMainSpan() const {
+ return Span(origin_main(), size_main());
+}
+
+void NormalizedRect::SetMainSpan(const Span& span) {
+ set_origin_main(span.start());
+ set_size_main(span.length());
+}
+
+void NormalizedRect::AlignMain(const Span& container,
+ LayoutAlignment alignment,
+ const Inset1D& margins) {
+ Span temp = GetMainSpan();
+ temp.Align(container, alignment, margins);
+ SetMainSpan(temp);
+}
+
+Span NormalizedRect::GetCrossSpan() const {
+ return Span(origin_cross(), size_cross());
+}
+
+void NormalizedRect::SetCrossSpan(const Span& span) {
+ set_origin_cross(span.start());
+ set_size_cross(span.length());
+}
+
+void NormalizedRect::AlignCross(const Span& container,
+ LayoutAlignment alignment,
+ const Inset1D& margins) {
+ Span temp = GetCrossSpan();
+ temp.Align(container, alignment, margins);
+ SetCrossSpan(temp);
+}
+
+void NormalizedRect::SetRect(int origin_main,
+ int origin_cross,
+ int size_main,
+ int size_cross) {
+ origin_.SetPoint(origin_main, origin_cross);
+ size_.SetSize(size_main, size_cross);
+}
+void NormalizedRect::SetByBounds(int origin_main,
+ int origin_cross,
+ int max_main,
+ int max_cross) {
+ origin_.SetPoint(origin_main, origin_cross);
+ size_.SetSize(std::max(0, max_main - origin_main),
+ std::max(0, max_cross - origin_cross));
+}
+void NormalizedRect::Inset(const NormalizedInsets& insets) {
+ Inset(insets.main_leading(), insets.cross_leading(), insets.main_trailing(),
+ insets.cross_trailing());
+}
+void NormalizedRect::Inset(int main, int cross) {
+ Inset(main, cross, main, cross);
+}
+void NormalizedRect::Inset(int main_leading,
+ int cross_leading,
+ int main_trailing,
+ int cross_trailing) {}
+void NormalizedRect::Offset(int main, int cross) {
+ origin_.Offset(main, cross);
+}
+
+bool NormalizedRect::operator==(const NormalizedRect& other) const {
+ return origin_ == other.origin_ && size_ == other.size_;
+}
+
+bool NormalizedRect::operator!=(const NormalizedRect& other) const {
+ return !(*this == other);
+}
+
+bool NormalizedRect::operator<(const NormalizedRect& other) const {
+ return std::tie(origin_, size_) < std::tie(other.origin_, other.size_);
+}
+
+std::string NormalizedRect::ToString() const {
+ return base::StringPrintf("(%s) [%s]", origin().ToString().c_str(),
+ size().ToString().c_str());
+}
+
+// Normalization and Denormalization -------------------------------------------
+
+NormalizedPoint Normalize(LayoutOrientation orientation,
+ const gfx::Point& point) {
+ switch (orientation) {
+ case LayoutOrientation::kHorizontal:
+ return NormalizedPoint(point.x(), point.y());
+ case LayoutOrientation::kVertical:
+ return NormalizedPoint(point.y(), point.x());
+ default:
+ DCHECK(false);
+ return NormalizedPoint(point.x(), point.y());
+ }
+}
+
+gfx::Point Denormalize(LayoutOrientation orientation,
+ const NormalizedPoint& point) {
+ switch (orientation) {
+ case LayoutOrientation::kHorizontal:
+ return gfx::Point(point.main(), point.cross());
+ case LayoutOrientation::kVertical:
+ return gfx::Point(point.cross(), point.main());
+ default:
+ DCHECK(false);
+ return gfx::Point(point.main(), point.cross());
+ }
+}
+
+NormalizedSize Normalize(LayoutOrientation orientation, const gfx::Size& size) {
+ switch (orientation) {
+ case LayoutOrientation::kHorizontal:
+ return NormalizedSize(size.width(), size.height());
+ case LayoutOrientation::kVertical:
+ return NormalizedSize(size.height(), size.width());
+ default:
+ DCHECK(false);
+ return NormalizedSize(size.width(), size.height());
+ }
+}
+
+gfx::Size Denormalize(LayoutOrientation orientation,
+ const NormalizedSize& size) {
+ switch (orientation) {
+ case LayoutOrientation::kHorizontal:
+ return gfx::Size(size.main(), size.cross());
+ case LayoutOrientation::kVertical:
+ return gfx::Size(size.cross(), size.main());
+ default:
+ DCHECK(false);
+ return gfx::Size(size.main(), size.cross());
+ }
+}
+
+NormalizedSizeBounds Normalize(LayoutOrientation orientation,
+ const SizeBounds& bounds) {
+ switch (orientation) {
+ case LayoutOrientation::kHorizontal:
+ return NormalizedSizeBounds(bounds.width(), bounds.height());
+ case LayoutOrientation::kVertical:
+ return NormalizedSizeBounds(bounds.height(), bounds.width());
+ default:
+ DCHECK(false);
+ return NormalizedSizeBounds(bounds.width(), bounds.height());
+ }
+}
+
+SizeBounds Denormalize(LayoutOrientation orientation,
+ const NormalizedSizeBounds& bounds) {
+ switch (orientation) {
+ case LayoutOrientation::kHorizontal:
+ return SizeBounds(bounds.main(), bounds.cross());
+ case LayoutOrientation::kVertical:
+ return SizeBounds(bounds.cross(), bounds.main());
+ default:
+ DCHECK(false);
+ return SizeBounds(bounds.main(), bounds.cross());
+ }
+}
+
+NormalizedInsets Normalize(LayoutOrientation orientation,
+ const gfx::Insets& insets) {
+ switch (orientation) {
+ case LayoutOrientation::kHorizontal:
+ return NormalizedInsets(insets.left(), insets.top(), insets.right(),
+ insets.bottom());
+ case LayoutOrientation::kVertical:
+ return NormalizedInsets(insets.top(), insets.left(), insets.bottom(),
+ insets.right());
+ default:
+ DCHECK(false);
+ return NormalizedInsets(insets.left(), insets.top(), insets.right(),
+ insets.bottom());
+ }
+}
+
+gfx::Insets Denormalize(LayoutOrientation orientation,
+ const NormalizedInsets& insets) {
+ switch (orientation) {
+ case LayoutOrientation::kHorizontal:
+ return gfx::Insets(insets.cross_leading(), insets.main_leading(),
+ insets.cross_trailing(), insets.main_trailing());
+ case LayoutOrientation::kVertical:
+ return gfx::Insets(insets.main_leading(), insets.cross_leading(),
+ insets.main_trailing(), insets.cross_trailing());
+ default:
+ DCHECK(false);
+ return gfx::Insets(insets.cross_leading(), insets.main_leading(),
+ insets.cross_trailing(), insets.main_trailing());
+ }
+}
+
+NormalizedRect Normalize(LayoutOrientation orientation,
+ const gfx::Rect& bounds) {
+ return NormalizedRect(Normalize(orientation, bounds.origin()),
+ Normalize(orientation, bounds.size()));
+}
+
+gfx::Rect Denormalize(LayoutOrientation orientation,
+ const NormalizedRect& bounds) {
+ return gfx::Rect(Denormalize(orientation, bounds.origin()),
+ Denormalize(orientation, bounds.size()));
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/layout/flex_layout_types_internal.h b/chromium/ui/views/layout/flex_layout_types_internal.h
new file mode 100644
index 00000000000..80b0231fda0
--- /dev/null
+++ b/chromium/ui/views/layout/flex_layout_types_internal.h
@@ -0,0 +1,367 @@
+// 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_LAYOUT_FLEX_LAYOUT_TYPES_INTERNAL_H_
+#define UI_VIEWS_LAYOUT_FLEX_LAYOUT_TYPES_INTERNAL_H_
+
+#include <string>
+
+#include "base/optional.h"
+#include "ui/views/layout/flex_layout_types.h"
+
+namespace gfx {
+class Insets;
+class Point;
+class Rect;
+class Size;
+} // namespace gfx
+
+namespace views {
+
+class SizeBounds;
+
+namespace internal {
+
+// Represents insets in a single dimension.
+class Inset1D {
+ public:
+ constexpr Inset1D() = default;
+ constexpr explicit Inset1D(int all) : leading_(all), trailing_(all) {}
+ constexpr Inset1D(int leading, int trailing)
+ : leading_(leading), trailing_(trailing) {}
+
+ constexpr int leading() const { return leading_; }
+ void set_leading(int leading) { leading_ = leading; }
+
+ constexpr int trailing() const { return trailing_; }
+ void set_trailing(int trailing) { trailing_ = trailing; }
+
+ constexpr int size() const { return leading_ + trailing_; }
+
+ void SetInsets(int leading, int trailing);
+ void Expand(int delta_leading, int delta_trailing);
+
+ constexpr bool is_empty() const { return leading_ == 0 && trailing_ == 0; }
+ bool operator==(const Inset1D& other) const;
+ bool operator!=(const Inset1D& other) const;
+ bool operator<(const Inset1D& other) const;
+
+ std::string ToString() const;
+
+ private:
+ int leading_ = 0;
+ int trailing_ = 0;
+};
+
+// Represents a line segment in one dimension with a starting point and length.
+class Span {
+ public:
+ constexpr Span() = default;
+ constexpr Span(int start, int length) : start_(start), length_(length) {}
+
+ constexpr int start() const { return start_; }
+ void set_start(int start) { start_ = start; }
+
+ constexpr int length() const { return length_; }
+ void set_length(int length) {
+ DCHECK_GE(length, 0);
+ length_ = length;
+ }
+
+ constexpr int end() const { return start_ + length_; }
+ void set_end(int end) {
+ DCHECK_GE(end, start_);
+ length_ = end - start_;
+ }
+
+ void SetSpan(int start, int length);
+
+ // Expands the span by |leading| at the front (reducing the value of start()
+ // if |leading| is positive) and by |trailing| at the end (increasing the
+ // value of end() if |trailing| is positive).
+ void Expand(int leading, int trailing);
+
+ // Opposite of Expand(). Shrinks each end of the span by the specified amount.
+ void Inset(int leading, int trailing);
+ void Inset(const Inset1D& insets);
+
+ // Centers the span in another span, with optional margins.
+ // Overflow is handled gracefully.
+ void Center(const Span& container, const Inset1D& margins = Inset1D());
+
+ // Aligns the span in another span, with optional margins, using the specified
+ // alignment. Overflow is handled gracefully.
+ void Align(const Span& container,
+ LayoutAlignment alignment,
+ const Inset1D& margins = Inset1D());
+
+ constexpr bool is_empty() const { return length_ == 0; }
+ bool operator==(const Span& other) const;
+ bool operator!=(const Span& other) const;
+ bool operator<(const Span& other) const;
+
+ std::string ToString() const;
+
+ private:
+ int start_ = 0;
+ int length_ = 0;
+};
+
+// Represents a point in layout space - that is, a point on the main and cross
+// axes of the layout (regardless of whether it is vertically or horizontally
+// oriented.
+class NormalizedPoint {
+ public:
+ constexpr NormalizedPoint() = default;
+ constexpr NormalizedPoint(int main, int cross) : main_(main), cross_(cross) {}
+
+ constexpr int main() const { return main_; }
+ void set_main(int main) { main_ = main; }
+
+ constexpr int cross() const { return cross_; }
+ void set_cross(int cross) { cross_ = cross; }
+
+ void SetPoint(int main, int cross);
+ void Offset(int delta_main, int delta_cross);
+
+ bool operator==(const NormalizedPoint& other) const;
+ bool operator!=(const NormalizedPoint& other) const;
+ bool operator<(const NormalizedPoint& other) const;
+
+ std::string ToString() const;
+
+ private:
+ int main_ = 0;
+ int cross_ = 0;
+};
+
+// Represents a size in layout space - that is, a size on the main and cross
+// axes of the layout (regardless of whether it is vertically or horizontally
+// oriented.
+class NormalizedSize {
+ public:
+ constexpr NormalizedSize() = default;
+ constexpr NormalizedSize(int main, int cross) : main_(main), cross_(cross) {}
+
+ constexpr int main() const { return main_; }
+ void set_main(int main) { main_ = main; }
+
+ constexpr int cross() const { return cross_; }
+ void set_cross(int cross) { cross_ = cross; }
+
+ void SetSize(int main, int cross);
+ void Enlarge(int delta_main, int delta_cross);
+ void SetToMax(int main, int cross);
+ void SetToMax(const NormalizedSize& other);
+ void SetToMin(int main, int cross);
+ void SetToMin(const NormalizedSize& other);
+
+ constexpr bool is_empty() const { return main_ == 0 || cross_ == 0; }
+
+ bool operator==(const NormalizedSize& other) const;
+ bool operator!=(const NormalizedSize& other) const;
+ bool operator<(const NormalizedSize& other) const;
+
+ std::string ToString() const;
+
+ private:
+ int main_ = 0;
+ int cross_ = 0;
+};
+
+// Represents insets in layout space - that is, insets on the main and cross
+// axes of the layout (regardless of whether it is vertically or horizontally
+// oriented.
+class NormalizedInsets {
+ public:
+ constexpr NormalizedInsets() = default;
+ constexpr explicit NormalizedInsets(int all) : main_(all), cross_(all) {}
+ constexpr NormalizedInsets(int main, int cross)
+ : main_(main), cross_(cross) {}
+ constexpr NormalizedInsets(const Inset1D& main, const Inset1D& cross)
+ : main_(main), cross_(cross) {}
+ constexpr NormalizedInsets(int main_leading,
+ int cross_leading,
+ int main_trailing,
+ int cross_trailing)
+ : main_(main_leading, main_trailing),
+ cross_(cross_leading, cross_trailing) {}
+
+ constexpr int main_leading() const { return main_.leading(); }
+ void set_main_leading(int main_leading) { main_.set_leading(main_leading); }
+
+ constexpr int main_trailing() const { return main_.trailing(); }
+ void set_main_trailing(int main_trailing) {
+ main_.set_trailing(main_trailing);
+ }
+
+ constexpr int main_size() const { return main_.size(); }
+
+ constexpr int cross_leading() const { return cross_.leading(); }
+ void set_cross_leading(int cross_leading) {
+ cross_.set_leading(cross_leading);
+ }
+
+ constexpr int cross_trailing() const { return cross_.trailing(); }
+ void set_cross_trailing(int cross_trailing) {
+ cross_.set_trailing(cross_trailing);
+ }
+
+ constexpr int cross_size() const { return cross_.size(); }
+
+ const Inset1D& main() const { return main_; }
+ void set_main(const Inset1D& main) { main_ = main; }
+
+ const Inset1D& cross() const { return cross_; }
+ void set_cross(const Inset1D& cross) { cross_ = cross; }
+
+ bool operator==(const NormalizedInsets& other) const;
+ bool operator!=(const NormalizedInsets& other) const;
+ bool operator<(const NormalizedInsets& other) const;
+
+ std::string ToString() const;
+
+ private:
+ Inset1D main_;
+ Inset1D cross_;
+};
+
+// Represents size bounds in layout space - that is, a set of size bounds using
+// the main and cross axes of the layout (regardless of whether it is vertically
+// or horizontally oriented).
+class NormalizedSizeBounds {
+ public:
+ NormalizedSizeBounds();
+ NormalizedSizeBounds(const base::Optional<int>& main,
+ const base::Optional<int>& cross);
+ explicit NormalizedSizeBounds(const NormalizedSize& size);
+ NormalizedSizeBounds(const NormalizedSizeBounds& size_bounds);
+
+ const base::Optional<int>& main() const { return main_; }
+ void set_main(const base::Optional<int>& main) { main_ = main; }
+
+ const base::Optional<int>& cross() const { return cross_; }
+ void set_cross(const base::Optional<int>& cross) { cross_ = cross; }
+
+ void Expand(int main, int cross);
+
+ bool operator==(const NormalizedSizeBounds& other) const;
+ bool operator!=(const NormalizedSizeBounds& other) const;
+ bool operator<(const NormalizedSizeBounds& other) const;
+
+ std::string ToString() const;
+
+ private:
+ base::Optional<int> main_;
+ base::Optional<int> cross_;
+};
+
+// Represents a rectangle in layout space - that is, a rectangle whose
+// dimensions align with the main and cross axis of the layout (regardless of
+// whether the layout is vertically or horizontally oriented).
+class NormalizedRect {
+ public:
+ constexpr NormalizedRect() = default;
+ constexpr NormalizedRect(const NormalizedPoint& origin,
+ const NormalizedSize& size)
+ : origin_(origin), size_(size) {}
+ constexpr NormalizedRect(const Span& main, const Span& cross)
+ : origin_(main.start(), cross.start()),
+ size_(main.length(), cross.length()) {}
+ constexpr NormalizedRect(int origin_main,
+ int origin_cross,
+ int size_main,
+ int size_cross)
+ : origin_(origin_main, origin_cross), size_(size_main, size_cross) {}
+
+ constexpr int origin_main() const { return origin_.main(); }
+ void set_origin_main(int main) { origin_.set_main(main); }
+
+ constexpr int origin_cross() const { return origin_.cross(); }
+ void set_origin_cross(int cross) { origin_.set_cross(cross); }
+
+ constexpr const NormalizedPoint& origin() const { return origin_; }
+ void set_origin(const NormalizedPoint& origin) { origin_ = origin; }
+
+ constexpr int size_main() const { return size_.main(); }
+ void set_size_main(int main) { size_.set_main(main); }
+
+ constexpr int size_cross() const { return size_.cross(); }
+ void set_size_cross(int cross) { size_.set_cross(cross); }
+
+ constexpr const NormalizedSize& size() const { return size_; }
+ void set_size(const NormalizedSize& size) { size_ = size; }
+
+ constexpr int max_main() const { return origin_.main() + size_.main(); }
+ constexpr int max_cross() const { return origin_.cross() + size_.cross(); }
+
+ Span GetMainSpan() const;
+ void SetMainSpan(const Span& span);
+ void AlignMain(const Span& container,
+ LayoutAlignment alignment,
+ const Inset1D& margins = Inset1D());
+
+ Span GetCrossSpan() const;
+ void SetCrossSpan(const Span& span);
+ void AlignCross(const Span& container,
+ LayoutAlignment alignment,
+ const Inset1D& margins = Inset1D());
+
+ void SetRect(int origin_main,
+ int origin_cross,
+ int size_main,
+ int size_cross);
+ void SetByBounds(int origin_main,
+ int origin_cross,
+ int max_main,
+ int max_cross);
+ void Inset(const NormalizedInsets& insets);
+ void Inset(int main, int cross);
+ void Inset(int main_leading,
+ int cross_leading,
+ int main_trailing,
+ int cross_trailing);
+ void Offset(int main, int cross);
+
+ constexpr bool is_empty() const { return size_.is_empty(); }
+ bool operator==(const NormalizedRect& other) const;
+ bool operator!=(const NormalizedRect& other) const;
+ bool operator<(const NormalizedRect& other) const;
+
+ std::string ToString() const;
+
+ private:
+ NormalizedPoint origin_;
+ NormalizedSize size_;
+};
+
+// Normalization and Denormalization -------------------------------------------
+
+NormalizedPoint Normalize(LayoutOrientation orientation,
+ const gfx::Point& point);
+gfx::Point Denormalize(LayoutOrientation orientation,
+ const NormalizedPoint& point);
+
+NormalizedSize Normalize(LayoutOrientation orientation, const gfx::Size& point);
+gfx::Size Denormalize(LayoutOrientation orientation,
+ const NormalizedSize& point);
+
+NormalizedSizeBounds Normalize(LayoutOrientation orientation,
+ const SizeBounds& point);
+SizeBounds Denormalize(LayoutOrientation orientation,
+ const NormalizedSizeBounds& point);
+
+NormalizedInsets Normalize(LayoutOrientation orientation,
+ const gfx::Insets& point);
+gfx::Insets Denormalize(LayoutOrientation orientation,
+ const NormalizedInsets& point);
+
+NormalizedRect Normalize(LayoutOrientation orientation, const gfx::Rect& rect);
+gfx::Rect Denormalize(LayoutOrientation orientation,
+ const NormalizedRect& rect);
+
+} // namespace internal
+} // namespace views
+
+#endif // UI_VIEWS_LAYOUT_FLEX_LAYOUT_TYPES_INTERNAL_H_
diff --git a/chromium/ui/views/layout/flex_layout_unittest.cc b/chromium/ui/views/layout/flex_layout_unittest.cc
new file mode 100644
index 00000000000..a33750b3ea8
--- /dev/null
+++ b/chromium/ui/views/layout/flex_layout_unittest.cc
@@ -0,0 +1,1730 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/layout/flex_layout.h"
+
+#include <stddef.h>
+#include <vector>
+
+#include "base/optional.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/views/border.h"
+#include "ui/views/layout/flex_layout_types.h"
+#include "ui/views/test/test_views.h"
+#include "ui/views/view.h"
+#include "ui/views/view_properties.h"
+
+namespace views {
+
+namespace {
+
+using base::Optional;
+using gfx::Insets;
+using gfx::Point;
+using gfx::Rect;
+using gfx::Size;
+
+class MockView : public View {
+ public:
+ void SetMinimumSize(const Size& minimum_size) {
+ minimum_size_ = minimum_size;
+ }
+
+ Size GetMinimumSize() const override {
+ return minimum_size_.value_or(GetPreferredSize());
+ }
+
+ void SetVisible(bool visible) override {
+ View::SetVisible(visible);
+ ++set_visible_count_;
+ }
+
+ int GetSetVisibleCount() const { return set_visible_count_; }
+
+ void ResetCounts() { set_visible_count_ = 0; }
+
+ private:
+ Optional<Size> minimum_size_;
+ int set_visible_count_ = 0;
+};
+
+// Custom flex rule that snaps a view between its preffered size and half that
+// size in each dimension.
+Size CustomFlexImpl(bool snap_to_zero,
+ const View* view,
+ const SizeBounds& maximum_size) {
+ const Size large_size = view->GetPreferredSize();
+ const Size small_size = Size(large_size.width() / 2, large_size.height() / 2);
+ int horizontal, vertical;
+ if (!maximum_size.width() || *maximum_size.width() > large_size.width()) {
+ horizontal = large_size.width();
+ } else if (snap_to_zero && *maximum_size.width() < small_size.width()) {
+ horizontal = 0;
+ } else {
+ horizontal = small_size.width();
+ }
+ if (!maximum_size.height() || *maximum_size.height() > large_size.height()) {
+ vertical = large_size.height();
+ } else if (snap_to_zero && *maximum_size.height() < small_size.height()) {
+ vertical = 0;
+ } else {
+ vertical = small_size.height();
+ }
+ return Size(horizontal, vertical);
+}
+
+class FlexLayoutTest : public testing::Test {
+ public:
+ void SetUp() override {
+ host_ = std::make_unique<View>();
+ layout_ = host_->SetLayoutManager(std::make_unique<FlexLayout>());
+ }
+
+ MockView* AddChild(const Size& preferred_size,
+ const Optional<Size>& minimum_size = Optional<Size>(),
+ bool visible = true) {
+ return AddChild(host_.get(), preferred_size, minimum_size, visible);
+ }
+
+ static MockView* AddChild(
+ View* parent,
+ const Size& preferred_size,
+ const Optional<Size>& minimum_size = Optional<Size>(),
+ bool visible = true) {
+ MockView* const child = new MockView();
+ child->SetPreferredSize(preferred_size);
+ if (minimum_size.has_value())
+ child->SetMinimumSize(minimum_size.value());
+ if (!visible)
+ child->SetVisible(false);
+ parent->AddChildView(child);
+ return child;
+ }
+
+ std::vector<Rect> GetChildBounds() const {
+ std::vector<Rect> result;
+ for (int i = 0; i < host_->child_count(); ++i) {
+ const View* const child = host_->child_at(i);
+ result.push_back(child->bounds());
+ }
+ return result;
+ }
+
+ protected:
+ // Preferred size or drop out.
+ static const FlexSpecification kDropOut;
+ static const FlexSpecification kDropOutHighPriority;
+
+ // Scale from preferred down to minimum or zero.
+ static const FlexSpecification kFlex1ScaleToMinimum;
+ static const FlexSpecification kFlex2ScaleToMinimum;
+ static const FlexSpecification kFlex1ScaleToMinimumHighPriority;
+ static const FlexSpecification kFlex1ScaleToZero;
+
+ // Scale from a minimum value up to infinity.
+ static const FlexSpecification kUnboundedSnapToMinimum;
+ static const FlexSpecification kUnboundedScaleToMinimumSnapToZero;
+ static const FlexSpecification kUnboundedScaleToZero;
+
+ // Custom flex which scales step-wise.
+ static const FlexSpecification kCustomFlex;
+ static const FlexSpecification kCustomFlexSnapToZero;
+
+ std::unique_ptr<View> host_;
+ FlexLayout* layout_;
+};
+
+const FlexSpecification FlexLayoutTest::kDropOut =
+ FlexSpecification::ForSizeRule(MinimumFlexSizeRule::kPreferredSnapToZero,
+ MaximumFlexSizeRule::kPreferred)
+ .WithWeight(0)
+ .WithOrder(2);
+const FlexSpecification FlexLayoutTest::kDropOutHighPriority =
+ FlexLayoutTest::kDropOut.WithOrder(1);
+const FlexSpecification FlexLayoutTest::kFlex1ScaleToZero =
+ FlexSpecification::ForSizeRule(MinimumFlexSizeRule::kScaleToZero,
+ MaximumFlexSizeRule::kPreferred)
+ .WithOrder(2);
+const FlexSpecification FlexLayoutTest::kFlex1ScaleToMinimum =
+ FlexSpecification::ForSizeRule(MinimumFlexSizeRule::kScaleToMinimum,
+ MaximumFlexSizeRule::kPreferred)
+ .WithOrder(2);
+const FlexSpecification FlexLayoutTest::kFlex2ScaleToMinimum =
+ FlexLayoutTest::kFlex1ScaleToMinimum.WithWeight(2);
+const FlexSpecification FlexLayoutTest::kFlex1ScaleToMinimumHighPriority =
+ FlexLayoutTest::kFlex1ScaleToMinimum.WithOrder(1);
+const FlexSpecification FlexLayoutTest::kUnboundedSnapToMinimum =
+ FlexSpecification::ForSizeRule(MinimumFlexSizeRule::kPreferredSnapToMinimum,
+ MaximumFlexSizeRule::kUnbounded)
+ .WithOrder(2);
+const FlexSpecification FlexLayoutTest::kUnboundedScaleToMinimumSnapToZero =
+ FlexSpecification::ForSizeRule(
+ MinimumFlexSizeRule::kScaleToMinimumSnapToZero,
+ MaximumFlexSizeRule::kUnbounded)
+ .WithOrder(2);
+const FlexSpecification FlexLayoutTest::kUnboundedScaleToZero =
+ FlexSpecification::ForSizeRule(MinimumFlexSizeRule::kScaleToZero,
+ MaximumFlexSizeRule::kUnbounded)
+ .WithOrder(2);
+
+const FlexSpecification FlexLayoutTest::kCustomFlex =
+ FlexSpecification::ForCustomRule(
+ base::BindRepeating(&CustomFlexImpl, false))
+ .WithOrder(2);
+const FlexSpecification FlexLayoutTest::kCustomFlexSnapToZero =
+ FlexSpecification::ForCustomRule(base::BindRepeating(&CustomFlexImpl, true))
+ .WithOrder(2);
+
+} // namespace
+
+// Size Tests ------------------------------------------------------------------
+
+TEST_F(FlexLayoutTest, GetMinimumSize_Empty) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(false);
+ EXPECT_EQ(Size(0, 0), host_->GetMinimumSize());
+}
+
+TEST_F(FlexLayoutTest, GetMinimumSize_Empty_ViewInsets) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(false);
+ host_->SetBorder(CreateEmptyBorder(5, 6, 7, 9));
+ EXPECT_EQ(Size(15, 12), host_->GetMinimumSize());
+}
+
+TEST_F(FlexLayoutTest, GetMinimumSize_Empty_InternalMargin_Collapsed) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
+}
+
+TEST_F(FlexLayoutTest, GetMinimumSize_Empty_InternalMargin_NotCollapsed) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(false);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ EXPECT_EQ(Size(15, 12), host_->GetMinimumSize());
+}
+
+TEST_F(FlexLayoutTest,
+ GetMinimumSize_Empty_InternalMargin_DefaultMarginHasNoEffect) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(false);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetDefaultChildMargins(gfx::Insets(11, 11));
+ EXPECT_EQ(Size(15, 12), host_->GetMinimumSize());
+}
+
+TEST_F(FlexLayoutTest, GetMinimumSize_MinimumCross_Horizontal) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMinimumCrossAxisSize(5);
+ EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
+ layout_->SetMinimumCrossAxisSize(10);
+ EXPECT_EQ(Size(9, 10), host_->GetMinimumSize());
+ host_->SetBorder(CreateEmptyBorder(2, 2, 2, 2));
+ EXPECT_EQ(Size(13, 14), host_->GetMinimumSize());
+}
+
+TEST_F(FlexLayoutTest, GetMinimumSize_MinimumCross_Vertical) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMinimumCrossAxisSize(5);
+ EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
+ layout_->SetMinimumCrossAxisSize(10);
+ EXPECT_EQ(Size(10, 7), host_->GetMinimumSize());
+ host_->SetBorder(CreateEmptyBorder(2, 2, 2, 2));
+ EXPECT_EQ(Size(14, 11), host_->GetMinimumSize());
+}
+
+// Visibility and Inclusion Tests ----------------------------------------------
+
+TEST_F(FlexLayoutTest, Layout_VisibilitySetBeforeInstall) {
+ // Since our test fixture creates a host and adds the layout manager right
+ // away, we need to create our own for this test.
+ std::unique_ptr<views::View> host = std::make_unique<views::View>();
+ View* child1 =
+ AddChild(host.get(), Size(10, 10), base::Optional<Size>(), false);
+ View* child2 =
+ AddChild(host.get(), Size(10, 10), base::Optional<Size>(), true);
+ host->SetLayoutManager(std::make_unique<FlexLayout>());
+
+ host->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+
+ child1->SetVisible(true);
+ child2->SetVisible(false);
+
+ host->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_VisibilitySetAfterInstall) {
+ // Unlike the last test, we'll use the built-in host and layout manager since
+ // they're already set up.
+ View* child1 = AddChild(Size(10, 10), base::Optional<Size>(), false);
+ View* child2 = AddChild(Size(10, 10), base::Optional<Size>(), true);
+
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+
+ child1->SetVisible(true);
+ child2->SetVisible(false);
+
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_VisibilitySetBeforeAdd) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11), Optional<Size>(), false);
+ View* child3 = AddChild(Size(17, 13));
+
+ host_->Layout();
+ EXPECT_EQ(true, layout_->IsHiddenByOwner(child2));
+ EXPECT_FALSE(child2->visible());
+ EXPECT_EQ(Rect(6, 5, 12, 10), child1->bounds());
+ EXPECT_EQ(Rect(18, 5, 17, 13), child3->bounds());
+ EXPECT_EQ(Size(44, 25), host_->GetPreferredSize());
+
+ // This should have no additional effect since the child is already invisible.
+ child2->SetVisible(false);
+ host_->Layout();
+ EXPECT_EQ(true, layout_->IsHiddenByOwner(child2));
+ EXPECT_FALSE(child2->visible());
+ EXPECT_EQ(Rect(6, 5, 12, 10), child1->bounds());
+ EXPECT_EQ(Rect(18, 5, 17, 13), child3->bounds());
+ EXPECT_EQ(Size(44, 25), host_->GetPreferredSize());
+
+ child2->SetVisible(true);
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(18, 5, 13, 11),
+ Rect(31, 5, 17, 13)};
+ EXPECT_EQ(false, layout_->IsHiddenByOwner(child2));
+ EXPECT_TRUE(child2->visible());
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, Layout_VisibilitySetAfterAdd) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+
+ child2->SetVisible(false);
+ host_->Layout();
+ EXPECT_EQ(true, layout_->IsHiddenByOwner(child2));
+ EXPECT_FALSE(child2->visible());
+ EXPECT_EQ(Rect(6, 5, 12, 10), child1->bounds());
+ EXPECT_EQ(Rect(18, 5, 17, 13), child3->bounds());
+ EXPECT_EQ(Size(44, 25), host_->GetPreferredSize());
+
+ child2->SetVisible(true);
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(18, 5, 13, 11),
+ Rect(31, 5, 17, 13)};
+ EXPECT_EQ(false, layout_->IsHiddenByOwner(child2));
+ EXPECT_TRUE(child2->visible());
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest,
+ Layout_ViewVisibilitySetNotContingentOnActualVisibility) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ layout_->SetFlexForView(child2, kDropOut);
+
+ // Layout makes child view invisible due to flex rule.
+ host_->SetSize(Size(40, 25));
+ host_->Layout();
+ EXPECT_EQ(false, layout_->IsHiddenByOwner(child2));
+ EXPECT_FALSE(child2->visible());
+ EXPECT_EQ(Rect(6, 5, 12, 10), child1->bounds());
+ EXPECT_EQ(Rect(18, 5, 17, 13), child3->bounds());
+ // Preferred size should still reflect child hidden due to flex rule.
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+
+ // Now we will make child explicitly hidden.
+ child2->SetVisible(false);
+ EXPECT_EQ(true, layout_->IsHiddenByOwner(child2));
+
+ // Layout is the same, but we should report that the view is hidden by owner.
+ host_->Layout();
+ EXPECT_EQ(true, layout_->IsHiddenByOwner(child2));
+ EXPECT_FALSE(child2->visible());
+ EXPECT_EQ(Rect(6, 5, 12, 10), child1->bounds());
+ EXPECT_EQ(Rect(18, 5, 17, 13), child3->bounds());
+ EXPECT_EQ(Size(44, 25), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, Layout_Exlcude) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ const View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ const View* child3 = AddChild(Size(17, 13));
+
+ layout_->SetViewExcluded(child2, true);
+ child2->SetBounds(3, 3, 3, 3);
+ host_->Layout();
+ EXPECT_EQ(true, layout_->IsViewExcluded(child2));
+ EXPECT_EQ(Rect(3, 3, 3, 3), child2->bounds());
+ EXPECT_EQ(Rect(6, 5, 12, 10), child1->bounds());
+ EXPECT_EQ(Rect(18, 5, 17, 13), child3->bounds());
+ EXPECT_EQ(Size(44, 25), host_->GetPreferredSize());
+
+ layout_->SetViewExcluded(child2, false);
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(18, 5, 13, 11),
+ Rect(31, 5, 17, 13)};
+ EXPECT_EQ(false, layout_->IsViewExcluded(child2));
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+}
+
+// Child Positioning Tests -----------------------------------------------------
+
+TEST_F(FlexLayoutTest, LayoutSingleView_Horizontal) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ View* child = AddChild(Size(12, 10));
+ host_->Layout();
+ EXPECT_EQ(Rect(6, 5, 12, 10), child->bounds());
+}
+
+TEST_F(FlexLayoutTest, LayoutSingleView_Vertical) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ View* child = AddChild(Size(12, 10));
+ host_->Layout();
+ EXPECT_EQ(Rect(6, 5, 12, 10), child->bounds());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_Horizontal_CrossStart) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ AddChild(Size(12, 10));
+ AddChild(Size(13, 11));
+ AddChild(Size(17, 13));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(18, 5, 13, 11),
+ Rect(31, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_Horizontal_CrossCenter) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kCenter);
+ AddChild(Size(12, 10));
+ AddChild(Size(13, 11));
+ AddChild(Size(17, 13));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 6, 12, 10), Rect(18, 6, 13, 11),
+ Rect(31, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_Horizontal_CrossEnd) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kEnd);
+ AddChild(Size(12, 10));
+ AddChild(Size(13, 11));
+ AddChild(Size(17, 13));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 8, 12, 10), Rect(18, 7, 13, 11),
+ Rect(31, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_Horizontal_CrossStretch) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStretch);
+ host_->SetSize(Size(100, 25));
+ AddChild(Size(12, 10));
+ AddChild(Size(13, 11));
+ AddChild(Size(17, 13));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 5, 12, 13), Rect(18, 5, 13, 13),
+ Rect(31, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_Vertical_CrossStart) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ AddChild(Size(12, 10));
+ AddChild(Size(13, 11));
+ AddChild(Size(17, 13));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(6, 15, 13, 11),
+ Rect(6, 26, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(32, 46), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_Vertical_CrossCenter) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kCenter);
+ AddChild(Size(12, 10));
+ AddChild(Size(13, 11));
+ AddChild(Size(17, 13));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(8, 5, 12, 10), Rect(8, 15, 13, 11),
+ Rect(6, 26, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(32, 46), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_Vertical_CrossEnd) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kEnd);
+ AddChild(Size(12, 10));
+ AddChild(Size(13, 11));
+ AddChild(Size(17, 13));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(11, 5, 12, 10), Rect(10, 15, 13, 11),
+ Rect(6, 26, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(32, 46), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_Vertical_CrossStretch) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStretch);
+ AddChild(Size(12, 10));
+ AddChild(Size(13, 11));
+ AddChild(Size(17, 13));
+ host_->SetSize(Size(32, 50));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 5, 17, 10), Rect(6, 15, 17, 11),
+ Rect(6, 26, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(32, 46), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest,
+ LayoutMultipleViews_MarginAndSpacing_NoCollapse_Horizontal) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(false);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(18, 5, 13, 11),
+ Rect(31, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(57, 25), host_->GetPreferredSize());
+
+ child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
+ host_->InvalidateLayout();
+ host_->Layout();
+ expected = std::vector<Rect>{Rect(27, 25, 12, 10), Rect(62, 5, 13, 11),
+ Rect(75, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(101, 64), host_->GetPreferredSize());
+
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ host_->InvalidateLayout();
+ layout_->SetDefaultChildMargins(gfx::Insets(0, 3));
+ host_->Layout();
+ expected = std::vector<Rect>{Rect(27, 25, 12, 10), Rect(63, 6, 13, 11),
+ Rect(80, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(109, 64), host_->GetPreferredSize());
+
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->InvalidateLayout();
+ host_->Layout();
+ expected = std::vector<Rect>{Rect(27, 25, 12, 10), Rect(63, 6, 13, 11),
+ Rect(79, 7, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(107, 64), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest,
+ LayoutMultipleViews_MarginAndSpacing_NoCollapse_Vertical) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(false);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->InvalidateLayout();
+ host_->Layout();
+ std::vector<Rect> expected{Rect(27, 25, 12, 10), Rect(7, 58, 13, 11),
+ Rect(8, 72, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(71, 94), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest,
+ LayoutMultipleViews_MarginAndSpacing_Collapse_Horizontal) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->InvalidateLayout();
+ host_->Layout();
+ std::vector<Rect> expected{Rect(21, 20, 12, 10), Rect(56, 5, 13, 11),
+ Rect(71, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(97, 52), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_MarginAndSpacing_Collapse_Vertical) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->InvalidateLayout();
+ host_->Layout();
+ std::vector<Rect> expected{Rect(21, 20, 12, 10), Rect(6, 52, 13, 11),
+ Rect(6, 65, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(56, 85), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_InteriorPadding) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(10));
+ View* child = AddChild(Size(13, 15));
+ AddChild(Size(17, 13));
+ child->SetProperty(views::kInternalPaddingKey, new Insets(1, 2, 4, 8));
+ host_->InvalidateLayout();
+ host_->Layout();
+ std::vector<Rect> expected{
+ Rect(8, 9, 13, 15),
+ Rect(23, 10, 17, 13),
+ };
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(50, 33), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_InteriorPadding_Margins) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(2));
+ View* child = AddChild(Size(13, 15));
+ View* child2 = AddChild(Size(17, 13));
+ child->SetProperty(views::kInternalPaddingKey, new Insets(1, 2, 4, 8));
+ child2->SetProperty(views::kMarginsKey, new Insets(5, 5, 5, 5));
+ host_->InvalidateLayout();
+ host_->Layout();
+ std::vector<Rect> expected{
+ Rect(4, 4, 13, 15),
+ Rect(17, 5, 17, 13),
+ };
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(43, 25), host_->GetPreferredSize());
+}
+
+TEST_F(FlexLayoutTest, LayoutMultipleViews_InteriorPadding_Additive) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(20));
+ View* child = AddChild(Size(13, 15));
+ View* child2 = AddChild(Size(17, 13));
+ child->SetProperty(views::kInternalPaddingKey, new Insets(1, 2, 4, 8));
+ child2->SetProperty(views::kInternalPaddingKey, new Insets(5, 5, 5, 5));
+ host_->InvalidateLayout();
+ host_->Layout();
+ std::vector<Rect> expected{
+ Rect(18, 19, 13, 15),
+ Rect(38, 15, 17, 13),
+ };
+ EXPECT_EQ(expected, GetChildBounds());
+ EXPECT_EQ(Size(70, 50), host_->GetPreferredSize());
+}
+
+// Alignment Tests -------------------------------------------------------------
+
+TEST_F(FlexLayoutTest, Layout_CrossStart) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->SetSize(Size(200, 200));
+ host_->Layout();
+ EXPECT_EQ(10, child1->origin().y());
+ EXPECT_EQ(5, child2->origin().y());
+ EXPECT_EQ(5, child3->origin().y());
+}
+
+TEST_F(FlexLayoutTest, Layout_CrossCenter) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kCenter);
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->SetSize(Size(200, 200));
+ host_->Layout();
+ EXPECT_EQ(94, child1->origin().y());
+ EXPECT_EQ(93, child2->origin().y());
+ EXPECT_EQ(92, child3->origin().y());
+}
+
+TEST_F(FlexLayoutTest, Layout_CrossEnd) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kEnd);
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->SetSize(Size(200, 200));
+ host_->Layout();
+ EXPECT_EQ(178, child1->origin().y());
+ EXPECT_EQ(182, child2->origin().y());
+ EXPECT_EQ(180, child3->origin().y());
+}
+
+TEST_F(FlexLayoutTest, Layout_CrossStretch) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStretch);
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->SetSize(Size(200, 200));
+ host_->Layout();
+ EXPECT_EQ(10, child1->origin().y());
+ EXPECT_EQ(5, child2->origin().y());
+ EXPECT_EQ(5, child3->origin().y());
+ EXPECT_EQ(178, child1->size().height());
+ EXPECT_EQ(188, child2->size().height());
+ EXPECT_EQ(188, child3->size().height());
+}
+
+TEST_F(FlexLayoutTest, Layout_AlignStart) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->SetSize(Size(105, 50));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(21, 20, 12, 10), Rect(56, 5, 13, 11),
+ Rect(71, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+}
+
+TEST_F(FlexLayoutTest, Layout_AlignCenter) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kCenter);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->SetSize(Size(105, 50));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(25, 20, 12, 10), Rect(60, 5, 13, 11),
+ Rect(75, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+}
+
+TEST_F(FlexLayoutTest, Layout_AlignEnd) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kEnd);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->SetSize(Size(105, 50));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(29, 20, 12, 10), Rect(64, 5, 13, 11),
+ Rect(79, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+}
+
+TEST_F(FlexLayoutTest, Layout_AddDroppedMargins) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(false);
+ layout_->SetInteriorMargin(Insets(5, 5, 5, 5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ View* child1 = AddChild(Size(10, 10));
+ View* child2 = AddChild(Size(10, 10));
+ View* child3 = AddChild(Size(10, 10));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ layout_->SetFlexForView(child2, kDropOut);
+ EXPECT_EQ(Size(30, 20), host_->GetMinimumSize());
+
+ host_->SetSize(Size(100, 50));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(5, 5, 10, 10), Rect(16, 6, 10, 10),
+ Rect(27, 5, 10, 10)};
+ EXPECT_EQ(expected, GetChildBounds());
+
+ host_->SetSize(Size(25, 50));
+ host_->Layout();
+ EXPECT_EQ(Rect(5, 5, 10, 10), child1->bounds());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_EQ(Rect(15, 5, 10, 10), child3->bounds());
+}
+
+// Flex Tests ------------------------------------------------------------------
+
+TEST_F(FlexLayoutTest, Layout_IgnoreMinimumSize_DropViews) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ host_->SetSize(Size(55, 50));
+ host_->Layout();
+ std::vector<Rect> expected{Rect(11, 10, 12, 10), Rect(36, 5, 13, 11),
+ Rect(51, 5, 17, 13)};
+ EXPECT_EQ(expected, GetChildBounds());
+
+ layout_->SetFlexForView(child1, kDropOut);
+ EXPECT_EQ(Size(77, 32), host_->GetPreferredSize());
+ EXPECT_EQ(Size(47, 25), host_->GetMinimumSize());
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_TRUE(child3->visible());
+ EXPECT_EQ(Rect(6, 5, 13, 11), child2->bounds());
+ EXPECT_EQ(Rect(21, 5, 17, 13), child3->bounds());
+
+ layout_->ClearFlexForView(child1);
+ layout_->SetFlexForView(child2, kDropOut);
+ EXPECT_EQ(Size(77, 32), host_->GetPreferredSize());
+ EXPECT_EQ(Size(62, 32), host_->GetMinimumSize());
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_TRUE(child3->visible());
+ EXPECT_EQ(Rect(11, 10, 12, 10), child1->bounds());
+ EXPECT_EQ(Rect(36, 5, 17, 13), child3->bounds());
+
+ layout_->ClearFlexForView(child2);
+ layout_->SetFlexForView(child3, kDropOut);
+ EXPECT_EQ(Size(77, 32), host_->GetPreferredSize());
+ EXPECT_EQ(Size(58, 32), host_->GetMinimumSize());
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+ EXPECT_EQ(Rect(11, 10, 12, 10), child1->bounds());
+ EXPECT_EQ(Rect(36, 5, 13, 11), child2->bounds());
+}
+
+TEST_F(FlexLayoutTest, Layout_IgnoreMinimumSize_DropInOrder) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ // Set flex separately; we'll test default flex later.
+ layout_->SetFlexForView(child1, kDropOut);
+ layout_->SetFlexForView(child2, kDropOut);
+ layout_->SetFlexForView(child3, kDropOut);
+ EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
+
+ host_->SetSize(Size(100, 50));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_TRUE(child3->visible());
+
+ host_->SetSize(Size(58, 50));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+
+ host_->SetSize(Size(57, 50));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+
+ // Since there's no room for child1, child2 becomes visible.
+ host_->SetSize(Size(28, 50));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+
+ host_->SetSize(Size(27, 50));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_IgnoreMinimumSize_DropInOrder_DefaultFlex) {
+ // Perform the same test as above but with default flex set instead.
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ layout_->SetDefaultFlex(kDropOut);
+ EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
+
+ host_->SetSize(Size(100, 50));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_TRUE(child3->visible());
+
+ host_->SetSize(Size(58, 50));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+
+ host_->SetSize(Size(57, 50));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+
+ // Since there's no room for child1, child2 becomes visible.
+ host_->SetSize(Size(28, 50));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+
+ host_->SetSize(Size(27, 50));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_IgnoreMinimumSize_DropByPriority) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(3));
+ View* child1 = AddChild(Size(12, 10));
+ View* child2 = AddChild(Size(13, 11));
+ View* child3 = AddChild(Size(17, 13));
+ child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+ child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
+ child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
+ layout_->SetDefaultFlex(kDropOut);
+ layout_->SetFlexForView(child3, kDropOutHighPriority);
+ EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
+
+ host_->SetSize(Size(100, 50));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_TRUE(child3->visible());
+
+ host_->SetSize(Size(65, 50));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_TRUE(child3->visible());
+
+ host_->SetSize(Size(40, 50));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_TRUE(child3->visible());
+
+ host_->SetSize(Size(20, 50));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_FALSE(child2->visible());
+ EXPECT_FALSE(child3->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_Flex_OneViewScales) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(10, 20), Size(5, 5));
+ View* child2 = AddChild(Size(10, 10));
+ layout_->SetFlexForView(child1, kFlex1ScaleToMinimum);
+
+ host_->SetSize(Size(20, 50));
+ host_->Layout();
+ EXPECT_EQ(Size(10, 20), child1->size());
+ EXPECT_EQ(Size(10, 10), child2->size());
+
+ host_->SetSize(Size(20, 35));
+ host_->Layout();
+ EXPECT_EQ(Size(10, 10), child1->size());
+ EXPECT_EQ(Size(10, 10), child2->size());
+
+ host_->SetSize(Size(20, 30));
+ host_->Layout();
+ EXPECT_EQ(Size(10, 5), child1->size());
+ EXPECT_EQ(Size(10, 10), child2->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_Flex_OneViewScales_BelowMinimum) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(10, 20), Size(5, 5));
+ View* child2 = AddChild(Size(10, 10));
+ layout_->SetFlexForView(child1, kFlex1ScaleToMinimum);
+
+ host_->SetSize(Size(20, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(10, 5), child1->size());
+ EXPECT_EQ(Size(10, 10), child2->size());
+}
+
+TEST_F(FlexLayoutTest,
+ Layout_Flex_OneViewScales_CausesSubsequentControlToDropOut) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(10, 20), Size(5, 5));
+ View* child2 = AddChild(Size(10, 10), Size(5, 5));
+ layout_->SetFlexForView(child1, kFlex1ScaleToMinimum);
+ layout_->SetFlexForView(child2, kDropOut);
+
+ host_->SetSize(Size(20, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(10, 10), child1->size());
+ EXPECT_FALSE(child2->visible());
+}
+
+TEST_F(FlexLayoutTest,
+ Layout_Flex_OneViewScales_CausesSubsequentFlexControlToDropOut) {
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(10, 20), Size(5, 5));
+ View* child2 = AddChild(Size(10, 10), Size(5, 5));
+ layout_->SetFlexForView(child1, kFlex1ScaleToMinimum);
+ layout_->SetFlexForView(child2, kFlex1ScaleToZero);
+
+ host_->SetSize(Size(20, 19));
+ host_->Layout();
+ // TODO(dfried): Make this work.
+ // EXPECT_EQ(Size(10, 9), child1->size());
+ EXPECT_EQ(Size(10, 7), child1->size());
+ EXPECT_FALSE(child2->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_Flex_TwoChildViews_EqualWeight) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ layout_->SetDefaultFlex(kFlex1ScaleToMinimum);
+ View* child1 = AddChild(Size(20, 10), Size(5, 5));
+ View* child2 = AddChild(Size(20, 10), Size(5, 5));
+
+ host_->SetSize(Size(45, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(15, 10), child1->size());
+ EXPECT_EQ(Size(15, 10), child2->size());
+
+ host_->SetSize(Size(60, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(20, 10), child1->size());
+ EXPECT_EQ(Size(20, 10), child2->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_Flex_TwoChildViews_DefaultFlex) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ layout_->SetDefaultFlex(kFlex1ScaleToMinimum);
+ View* child1 = AddChild(Size(20, 10), Size(5, 5));
+ View* child2 = AddChild(Size(20, 10), Size(5, 5));
+
+ host_->SetSize(Size(45, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(15, 10), child1->size());
+ EXPECT_EQ(Size(15, 10), child2->size());
+
+ host_->SetSize(Size(60, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(20, 10), child1->size());
+ EXPECT_EQ(Size(20, 10), child2->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_Flex_TwoChildViews_UnequalWeight) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(20, 10), Size(5, 5));
+ View* child2 = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child1, kFlex1ScaleToMinimum);
+ layout_->SetFlexForView(child2, kFlex2ScaleToMinimum);
+
+ host_->SetSize(Size(45, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(12, 10), child1->size());
+ EXPECT_EQ(Size(18, 10), child2->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_Flex_TwoChildViews_UnequalWeight_FirstAtMax) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(20, 10), Size(5, 5));
+ View* child2 = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child1, kFlex2ScaleToMinimum);
+ layout_->SetFlexForView(child2, kFlex1ScaleToMinimum);
+
+ host_->SetSize(Size(50, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(20, 10), child1->size());
+ EXPECT_EQ(Size(15, 10), child2->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_Flex_TwoChildViews_UnequalWeight_SecondAtMax) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(20, 10), Size(5, 5));
+ View* child2 = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child1, kFlex1ScaleToMinimum);
+ layout_->SetFlexForView(child2, kFlex2ScaleToMinimum);
+
+ host_->SetSize(Size(50, 20));
+ host_->Layout();
+
+ // TODO(dfried): Make this work.
+ // EXPECT_EQ(Size(15, 10), child1->size());
+ EXPECT_EQ(Size(14, 10), child1->size());
+ EXPECT_EQ(Size(20, 10), child2->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_Flex_TwoChildViews_Priority) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(20, 10), Size(5, 5));
+ View* child2 = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child1, kFlex1ScaleToMinimum);
+ layout_->SetFlexForView(child2, kFlex1ScaleToMinimumHighPriority);
+
+ host_->SetSize(Size(50, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(15, 10), child1->size());
+ EXPECT_EQ(Size(20, 10), child2->size());
+
+ host_->SetSize(Size(35, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(5, 10), child1->size());
+ EXPECT_EQ(Size(15, 10), child2->size());
+}
+
+TEST_F(FlexLayoutTest,
+ Layout_Flex_TwoChildViews_Priority_LowerPriorityDropsOut) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child1 = AddChild(Size(20, 10), Size(5, 5));
+ View* child2 = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child1, kFlex1ScaleToZero);
+ layout_->SetFlexForView(child2, kFlex1ScaleToMinimumHighPriority);
+
+ host_->SetSize(Size(35, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(20, 10), child2->size());
+ EXPECT_FALSE(child1->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_FlexRule_UnboundedSnapToMinimum) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child, kUnboundedSnapToMinimum);
+
+ host_->SetSize(Size(35, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(25, 10), child->size());
+
+ host_->SetSize(Size(30, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(20, 10), child->size());
+
+ host_->SetSize(Size(29, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(5, 10), child->size());
+
+ host_->SetSize(Size(25, 10));
+ host_->Layout();
+ EXPECT_EQ(Size(5, 5), child->size());
+
+ // This is actually less space than the child needs, but its flex rule does
+ // not allow it to drop out.
+ host_->SetSize(Size(10, 10));
+ host_->Layout();
+ EXPECT_EQ(Size(5, 5), child->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_FlexRule_UnboundedScaleToMinimumSnapToZero) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child, kUnboundedScaleToMinimumSnapToZero);
+
+ host_->SetSize(Size(35, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(25, 10), child->size());
+
+ host_->SetSize(Size(30, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(20, 10), child->size());
+
+ host_->SetSize(Size(29, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(19, 10), child->size());
+
+ host_->SetSize(Size(25, 16));
+ host_->Layout();
+ EXPECT_EQ(Size(15, 6), child->size());
+
+ host_->SetSize(Size(25, 10));
+ host_->Layout();
+ EXPECT_FALSE(child->visible());
+
+ host_->SetSize(Size(15, 15));
+ host_->Layout();
+ EXPECT_EQ(Size(5, 5), child->size());
+
+ host_->SetSize(Size(14, 15));
+ host_->Layout();
+ EXPECT_FALSE(child->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_FlexRule_UnboundedScaleToZero) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ // Because we are using a flex rule that scales all the way to zero, ensure
+ // that the child view's minimum size is *not* respected.
+ View* child = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child, kUnboundedScaleToZero);
+
+ host_->SetSize(Size(35, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(25, 10), child->size());
+
+ host_->SetSize(Size(30, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(20, 10), child->size());
+
+ host_->SetSize(Size(29, 25));
+ host_->Layout();
+ EXPECT_EQ(Size(19, 10), child->size());
+
+ host_->SetSize(Size(25, 16));
+ host_->Layout();
+ EXPECT_EQ(Size(15, 6), child->size());
+
+ host_->SetSize(Size(25, 10));
+ host_->Layout();
+ EXPECT_FALSE(child->visible());
+
+ host_->SetSize(Size(15, 15));
+ host_->Layout();
+ EXPECT_EQ(Size(5, 5), child->size());
+
+ host_->SetSize(Size(14, 14));
+ host_->Layout();
+ EXPECT_EQ(Size(4, 4), child->size());
+
+ host_->SetSize(Size(9, 14));
+ host_->Layout();
+ EXPECT_FALSE(child->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_FlexRule_CustomFlexRule) {
+ constexpr int kFullSize = 50;
+ constexpr int kHalfSize = 25;
+
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child = AddChild(Size(kFullSize, kFullSize));
+ layout_->SetFlexForView(child, kCustomFlex);
+
+ host_->SetSize(Size(100, 100));
+ host_->Layout();
+ EXPECT_EQ(Size(kFullSize, kFullSize), child->size());
+
+ host_->SetSize(Size(100, 50));
+ host_->Layout();
+ EXPECT_EQ(Size(kFullSize, kHalfSize), child->size());
+
+ host_->SetSize(Size(50, 100));
+ host_->Layout();
+ EXPECT_EQ(Size(kHalfSize, kFullSize), child->size());
+
+ host_->SetSize(Size(45, 40));
+ host_->Layout();
+ EXPECT_EQ(Size(kHalfSize, kHalfSize), child->size());
+
+ // Custom flex rule does not go below half size.
+ host_->SetSize(Size(20, 20));
+ host_->Layout();
+ EXPECT_EQ(Size(kHalfSize, kHalfSize), child->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_FlexRule_CustomFlexRule_WithNonFlex) {
+ constexpr int kFullSize = 50;
+ constexpr int kHalfSize = 25;
+
+ layout_->SetOrientation(LayoutOrientation::kVertical);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child = AddChild(Size(kFullSize, kFullSize));
+ AddChild(Size(10, 10));
+ layout_->SetFlexForView(child, kCustomFlex);
+
+ host_->SetSize(Size(100, 100));
+ host_->Layout();
+ EXPECT_EQ(Size(kFullSize, kFullSize), child->size());
+
+ host_->SetSize(Size(100, 65));
+ host_->Layout();
+ EXPECT_EQ(Size(kFullSize, kHalfSize), child->size());
+
+ host_->SetSize(Size(50, 100));
+ host_->Layout();
+ EXPECT_EQ(Size(kHalfSize, kFullSize), child->size());
+
+ host_->SetSize(Size(45, 40));
+ host_->Layout();
+ EXPECT_EQ(Size(kHalfSize, kHalfSize), child->size());
+}
+
+TEST_F(FlexLayoutTest, Layout_FlexRule_CustomFlexRule_ShrinkToZero) {
+ constexpr int kFullSize = 50;
+ constexpr int kHalfSize = 25;
+
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ View* child = AddChild(Size(kFullSize, kFullSize));
+ layout_->SetFlexForView(child, kCustomFlexSnapToZero);
+
+ host_->SetSize(Size(100, 100));
+ host_->Layout();
+ EXPECT_EQ(Size(kFullSize, kFullSize), child->size());
+
+ host_->SetSize(Size(100, 50));
+ host_->Layout();
+ EXPECT_EQ(Size(kFullSize, kHalfSize), child->size());
+
+ host_->SetSize(Size(50, 100));
+ host_->Layout();
+ EXPECT_EQ(Size(kHalfSize, kFullSize), child->size());
+
+ host_->SetSize(Size(45, 40));
+ host_->Layout();
+ EXPECT_EQ(Size(kHalfSize, kHalfSize), child->size());
+
+ host_->SetSize(Size(20, 20));
+ host_->Layout();
+ EXPECT_FALSE(child->visible());
+}
+
+TEST_F(FlexLayoutTest, Layout_OnlyCallsSetViewVisibilityWhenNecessary) {
+ layout_->SetOrientation(LayoutOrientation::kHorizontal);
+ layout_->SetCollapseMargins(true);
+ layout_->SetInteriorMargin(Insets(5));
+ layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ layout_->SetDefaultChildMargins(gfx::Insets(5));
+ MockView* child1 = AddChild(Size(20, 10), Size(5, 5));
+ MockView* child2 = AddChild(Size(20, 10), Size(5, 5));
+ layout_->SetFlexForView(child1, kFlex1ScaleToZero);
+ layout_->SetFlexForView(child2, kFlex1ScaleToMinimumHighPriority);
+
+ child1->ResetCounts();
+ child2->ResetCounts();
+ host_->SetSize(Size(40, 20));
+ host_->Layout();
+ EXPECT_TRUE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_EQ(0, child1->GetSetVisibleCount());
+ EXPECT_EQ(0, child2->GetSetVisibleCount());
+
+ host_->SetSize(Size(35, 20));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_EQ(1, child1->GetSetVisibleCount());
+ EXPECT_EQ(0, child2->GetSetVisibleCount());
+
+ child1->ResetCounts();
+ child2->ResetCounts();
+ host_->SetSize(Size(30, 20));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_EQ(0, child1->GetSetVisibleCount());
+ EXPECT_EQ(0, child2->GetSetVisibleCount());
+
+ child1->SetVisible(false);
+ child1->ResetCounts();
+
+ host_->SetSize(Size(40, 20));
+ host_->Layout();
+ EXPECT_FALSE(child1->visible());
+ EXPECT_TRUE(child2->visible());
+ EXPECT_EQ(0, child1->GetSetVisibleCount());
+ EXPECT_EQ(0, child2->GetSetVisibleCount());
+}
+
+// Nested Layout Tests ---------------------------------------------------------
+
+class NestedFlexLayoutTest : public FlexLayoutTest {
+ public:
+ void AddChildren(int num_children) {
+ for (int i = 0; i < num_children; ++i) {
+ View* v = new View;
+ FlexLayout* layout = v->SetLayoutManager(std::make_unique<FlexLayout>());
+ host_->AddChildView(v);
+ children_.push_back(v);
+ layouts_.push_back(layout);
+ }
+ }
+
+ View* AddGrandchild(
+ int child_index,
+ const gfx::Size& preferred,
+ const base::Optional<gfx::Size>& minimum = base::Optional<gfx::Size>()) {
+ return AddChild(children_[child_index - 1], preferred, minimum);
+ }
+
+ View* child(int child_index) const { return children_[child_index - 1]; }
+
+ FlexLayout* layout(int child_index) const {
+ return layouts_[child_index - 1];
+ }
+
+ View* grandchild(int child_index, int grandchild_index) const {
+ return children_[child_index - 1]->child_at(grandchild_index - 1);
+ }
+
+ private:
+ std::vector<FlexLayout*> layouts_;
+ std::vector<View*> children_;
+};
+
+TEST_F(NestedFlexLayoutTest, Layout_OppositeOrientation) {
+ AddChildren(2);
+ AddGrandchild(1, gfx::Size(5, 5));
+ AddGrandchild(1, gfx::Size(5, 5));
+ AddGrandchild(2, gfx::Size(6, 6));
+ AddGrandchild(2, gfx::Size(6, 6));
+
+ layout_->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCollapseMargins(false)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart)
+ .SetDefaultChildMargins(gfx::Insets(2, 3, 4, 5))
+ .SetInteriorMargin(gfx::Insets(4, 3, 2, 1));
+
+ layout(1)
+ ->SetOrientation(LayoutOrientation::kVertical)
+ .SetCollapseMargins(true)
+ .SetDefaultChildMargins(gfx::Insets(2))
+ .SetInteriorMargin(gfx::Insets(1));
+
+ layout(2)
+ ->SetOrientation(LayoutOrientation::kVertical)
+ .SetCollapseMargins(true)
+ .SetDefaultChildMargins(gfx::Insets(1))
+ .SetInteriorMargin(gfx::Insets(2));
+
+ EXPECT_EQ(gfx::Size(39, 29), host_->GetPreferredSize());
+ host_->SetSize(gfx::Size(50, 30));
+ host_->Layout();
+ EXPECT_EQ(gfx::Rect(6, 6, 9, 16), child(1)->bounds());
+ EXPECT_EQ(gfx::Rect(23, 6, 10, 17), child(2)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 2, 5, 5), grandchild(1, 1)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 9, 5, 5), grandchild(1, 2)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 2, 6, 6), grandchild(2, 1)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 9, 6, 6), grandchild(2, 2)->bounds());
+}
+
+TEST_F(NestedFlexLayoutTest, Layout_SameOrientation) {
+ AddChildren(2);
+ AddGrandchild(1, gfx::Size(5, 5));
+ AddGrandchild(1, gfx::Size(5, 5));
+ AddGrandchild(2, gfx::Size(6, 6));
+ AddGrandchild(2, gfx::Size(6, 6));
+
+ layout_->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCollapseMargins(false)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart)
+ .SetDefaultChildMargins(gfx::Insets(2, 3, 4, 5))
+ .SetInteriorMargin(gfx::Insets(4, 3, 2, 1));
+
+ layout(1)
+ ->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCollapseMargins(true)
+ .SetDefaultChildMargins(gfx::Insets(2))
+ .SetInteriorMargin(gfx::Insets(1));
+
+ layout(2)
+ ->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCollapseMargins(true)
+ .SetDefaultChildMargins(gfx::Insets(1))
+ .SetInteriorMargin(gfx::Insets(2));
+
+ EXPECT_EQ(gfx::Size(53, 22), host_->GetPreferredSize());
+ host_->SetSize(gfx::Size(60, 30));
+ host_->Layout();
+ EXPECT_EQ(gfx::Rect(6, 6, 16, 9), child(1)->bounds());
+ EXPECT_EQ(gfx::Rect(30, 6, 17, 10), child(2)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 2, 5, 5), grandchild(1, 1)->bounds());
+ EXPECT_EQ(gfx::Rect(9, 2, 5, 5), grandchild(1, 2)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 2, 6, 6), grandchild(2, 1)->bounds());
+ EXPECT_EQ(gfx::Rect(9, 2, 6, 6), grandchild(2, 2)->bounds());
+}
+
+TEST_F(NestedFlexLayoutTest, Layout_Flex) {
+ const FlexSpecification flex_specification = FlexSpecification::ForSizeRule(
+ MinimumFlexSizeRule::kScaleToZero, MaximumFlexSizeRule::kPreferred);
+
+ AddChildren(2);
+ AddGrandchild(1, gfx::Size(5, 5));
+ AddGrandchild(1, gfx::Size(5, 5));
+ AddGrandchild(2, gfx::Size(6, 6));
+ AddGrandchild(2, gfx::Size(6, 6));
+
+ layout_->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCollapseMargins(true)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart)
+ .SetDefaultChildMargins(gfx::Insets(2))
+ .SetInteriorMargin(gfx::Insets(2))
+ .SetFlexForView(child(1), flex_specification)
+ .SetFlexForView(child(2), flex_specification);
+
+ layout(1)
+ ->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCollapseMargins(true)
+ .SetDefaultChildMargins(gfx::Insets(2))
+ .SetInteriorMargin(gfx::Insets(2))
+ .SetFlexForView(grandchild(1, 1), flex_specification)
+ .SetFlexForView(grandchild(1, 2), flex_specification);
+
+ layout(2)
+ ->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCollapseMargins(true)
+ .SetDefaultChildMargins(gfx::Insets(2))
+ .SetInteriorMargin(gfx::Insets(2))
+ .SetFlexForView(grandchild(2, 1), flex_specification)
+ .SetFlexForView(grandchild(2, 2), flex_specification);
+
+ EXPECT_EQ(gfx::Size(40, 14), host_->GetPreferredSize());
+ host_->SetSize(gfx::Size(20, 15));
+ host_->Layout();
+ EXPECT_EQ(gfx::Rect(2, 2, 7, 9), child(1)->bounds());
+ EXPECT_EQ(gfx::Rect(11, 2, 7, 10), child(2)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 2, 1, 5), grandchild(1, 1)->bounds());
+ EXPECT_FALSE(grandchild(1, 2)->visible());
+ EXPECT_EQ(gfx::Rect(2, 2, 1, 6), grandchild(2, 1)->bounds());
+ EXPECT_FALSE(grandchild(2, 2)->visible());
+
+ host_->SetSize(gfx::Size(25, 15));
+ host_->Layout();
+ EXPECT_EQ(gfx::Rect(2, 2, 10, 9), child(1)->bounds());
+ EXPECT_EQ(gfx::Rect(14, 2, 9, 10), child(2)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 2, 2, 5), grandchild(1, 1)->bounds());
+ EXPECT_EQ(gfx::Rect(6, 2, 2, 5), grandchild(1, 2)->bounds());
+ EXPECT_EQ(gfx::Rect(2, 2, 2, 6), grandchild(2, 1)->bounds());
+ EXPECT_EQ(gfx::Rect(6, 2, 1, 6), grandchild(2, 2)->bounds());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/layout/grid_layout_unittest.cc b/chromium/ui/views/layout/grid_layout_unittest.cc
index c5c3242d065..e4062dbc9a1 100644
--- a/chromium/ui/views/layout/grid_layout_unittest.cc
+++ b/chromium/ui/views/layout/grid_layout_unittest.cc
@@ -827,13 +827,6 @@ TEST_F(GridLayoutTest, MinimumPreferredSize) {
// GridLayout must guard against this as it hasn't yet updated the internal
// structures it uses to calculate Layout, so will give bogus results.
TEST_F(GridLayoutTest, LayoutOnAddDeath) {
- // gtest death tests, such as EXPECT_DCHECK_DEATH(), can not work in the
- // presence of fork() and other process launching. In views-mus, we have
- // already launched additional processes for our service manager. Performing
- // this test under mus is impossible.
- if (PlatformTestHelper::IsMus())
- return;
-
ColumnSet* set = layout()->AddColumnSet(0);
set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, GridLayout::USE_PREF, 0,
0);
diff --git a/chromium/ui/views/layout/layout_manager.cc b/chromium/ui/views/layout/layout_manager.cc
index 877a9f31139..db1a13f0dff 100644
--- a/chromium/ui/views/layout/layout_manager.cc
+++ b/chromium/ui/views/layout/layout_manager.cc
@@ -4,6 +4,7 @@
#include "ui/views/layout/layout_manager.h"
+#include "base/auto_reset.h"
#include "ui/views/view.h"
namespace views {
@@ -39,4 +40,12 @@ void LayoutManager::ViewAdded(View* host, View* view) {
void LayoutManager::ViewRemoved(View* host, View* view) {
}
+void LayoutManager::ViewVisibilitySet(View* host, View* view, bool visible) {}
+
+void LayoutManager::SetViewVisibility(View* view, bool visible) {
+ DCHECK_EQ(view->parent()->GetLayoutManager(), this);
+ base::AutoReset<View*> setter(&view_setting_visibility_on_, view);
+ view->SetVisible(visible);
+}
+
} // namespace views
diff --git a/chromium/ui/views/layout/layout_manager.h b/chromium/ui/views/layout/layout_manager.h
index ee1bfda10c0..4cd0e8a456d 100644
--- a/chromium/ui/views/layout/layout_manager.h
+++ b/chromium/ui/views/layout/layout_manager.h
@@ -71,6 +71,20 @@ class VIEWS_EXPORT LayoutManager {
// been installed on. This function allows the LayoutManager to cleanup any
// state it has kept specific to a View.
virtual void ViewRemoved(View* host, View* view);
+
+ // Called when View::SetVisible() is called by external code. Classes derived
+ // from LayoutManager can call SetViewVisibility() below to avoid triggering
+ // this event.
+ virtual void ViewVisibilitySet(View* host, View* view, bool visible);
+
+ protected:
+ // Sets the visibility of a view without triggering ViewVisibilitySet().
+ // During Layout(), use this method instead of View::SetVisibility().
+ void SetViewVisibility(View* view, bool visible);
+
+ private:
+ friend class views::View;
+ View* view_setting_visibility_on_ = nullptr;
};
} // namespace views
diff --git a/chromium/ui/views/linux_ui/linux_ui.h b/chromium/ui/views/linux_ui/linux_ui.h
index bebe2a6fe06..6743cb664c9 100644
--- a/chromium/ui/views/linux_ui/linux_ui.h
+++ b/chromium/ui/views/linux_ui/linux_ui.h
@@ -14,8 +14,8 @@
#include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
#include "ui/gfx/skia_font_delegate.h"
#include "ui/shell_dialogs/shell_dialog_linux.h"
+#include "ui/views/buildflags.h"
#include "ui/views/controls/button/button.h"
-#include "ui/views/features.h"
#include "ui/views/linux_ui/status_icon_linux.h"
#include "ui/views/views_export.h"
diff --git a/chromium/ui/views/masked_targeter_delegate.cc b/chromium/ui/views/masked_targeter_delegate.cc
index d0c697ecbf0..97a0f34aac3 100644
--- a/chromium/ui/views/masked_targeter_delegate.cc
+++ b/chromium/ui/views/masked_targeter_delegate.cc
@@ -4,7 +4,7 @@
#include "ui/views/masked_targeter_delegate.h"
-#include "ui/gfx/path.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/view.h"
@@ -18,7 +18,7 @@ bool MaskedTargeterDelegate::DoesIntersectRect(const View* target,
return false;
// Early return if |mask| is not a valid hit test mask.
- gfx::Path mask;
+ SkPath mask;
if (!GetHitTestMask(&mask))
return false;
diff --git a/chromium/ui/views/masked_targeter_delegate.h b/chromium/ui/views/masked_targeter_delegate.h
index ec56d34ada8..26974cca473 100644
--- a/chromium/ui/views/masked_targeter_delegate.h
+++ b/chromium/ui/views/masked_targeter_delegate.h
@@ -10,8 +10,9 @@
#include "ui/views/view_targeter_delegate.h"
#include "ui/views/views_export.h"
+class SkPath;
+
namespace gfx {
-class Path;
class Rect;
}
@@ -29,7 +30,7 @@ class VIEWS_EXPORT MaskedTargeterDelegate : public ViewTargeterDelegate {
// Sets the hit-test mask for the view which implements this interface,
// in that view's local coordinate space. Returns whether a valid mask
// has been set in |mask|.
- virtual bool GetHitTestMask(gfx::Path* mask) const = 0;
+ virtual bool GetHitTestMask(SkPath* mask) const = 0;
// ViewTargeterDelegate:
bool DoesIntersectRect(const View* target,
diff --git a/chromium/ui/views/mus/BUILD.gn b/chromium/ui/views/mus/BUILD.gn
index 8740e56c70d..aa466e856e6 100644
--- a/chromium/ui/views/mus/BUILD.gn
+++ b/chromium/ui/views/mus/BUILD.gn
@@ -104,216 +104,3 @@ group("for_mojo_application") {
":mus",
]
}
-
-jumbo_static_library("test_support") {
- testonly = true
-
- sources = [
- "../test/native_widget_factory_aura_mus.cc",
- "mus_client_test_api.h",
- "views_mus_test_suite.cc",
- "views_mus_test_suite.h",
- ]
-
- deps = [
- ":mus",
- "//base",
- "//base/test:test_support",
- "//mojo/core/embedder",
- "//services/catalog:lib",
- "//services/service_manager/background:lib",
- "//services/service_manager/public/cpp",
- "//services/ws/common",
- "//testing/gtest",
- "//ui/aura",
- "//ui/aura:test_support",
- "//ui/compositor:test_support",
- "//ui/gl:test_support",
- "//ui/resources",
- "//ui/resources:ui_test_pak",
- "//ui/views",
- "//ui/views:test_support_internal",
- ]
-
- if (use_ozone) {
- deps += [ "//ui/ozone" ]
- }
-
- data_deps = [
- ":views_mus_tests_catalog",
- "//services/ws/ime/test_ime_driver",
- "//ui/resources:ui_test_pak_data",
- ]
-}
-
-test("views_mus_unittests") {
- testonly = true
-
- sources = [
- "ax_remote_host_unittest.cc",
- "ax_tree_source_mus_unittest.cc",
- "desktop_window_tree_host_mus_unittest.cc",
- "run_all_unittests_mus.cc",
- "screen_mus_unittest.cc",
- ]
-
- configs += [ "//build/config:precompiled_headers" ]
-
- deps = [
- ":mus",
- ":test_support",
- "//base",
- "//base:i18n",
- "//base/test:test_support",
- "//cc",
- "//net",
- "//services/ws/public/mojom",
- "//services/ws/test_ws:mojom",
- "//skia",
- "//testing/gtest",
- "//third_party/icu",
- "//ui/accessibility",
- "//ui/accessibility/mojom",
- "//ui/aura",
- "//ui/aura:test_support",
- "//ui/base",
- "//ui/base:test_support",
- "//ui/base/ime",
- "//ui/compositor:test_support",
- "//ui/events:dom_keycode_converter",
- "//ui/events:events_base",
- "//ui/events:test_support",
- "//ui/events/platform",
- "//ui/gfx:test_support",
- "//ui/gfx/geometry",
- "//ui/native_theme",
- "//ui/strings",
- "//ui/touch_selection",
- "//ui/views",
- "//ui/views:test_support_internal",
- "//ui/views:views_unittests_sources",
- "//ui/views/mus/remote_view:tests",
- "//ui/wm",
- "//url",
- ]
-
- data_deps = [
- ":views_mus_tests_catalog_copy",
- "//services/ws/ime/test_ime_driver",
- "//services/ws/test_ws",
- ]
-
- if (is_win) {
- deps += [
- "//build/win:default_exe_manifest",
- "//third_party/iaccessible2",
- "//third_party/wtl",
- ]
- libs = [
- "imm32.lib",
- "oleacc.lib",
- "comctl32.lib",
- ]
- }
-
- if (use_x11) {
- configs += [
- "//build/config/linux:x11",
- "//build/config/linux:xext",
- ]
- deps += [
- "//ui/events/devices",
- "//ui/events/platform/x11",
- "//ui/gfx/x",
- ]
- }
-}
-
-# Tests that must run sequentially because they access system-wide features
-# like capture.
-test("views_mus_interactive_ui_tests") {
- testonly = true
-
- sources = [
- "../widget/widget_interactive_uitest.cc",
- "clipboard_unittest.cc",
- "drag_interactive_uitest.cc",
- "interactive_ui_tests_mus.cc",
- ]
-
- deps = [
- ":mus",
- ":test_support",
- "//base",
- "//mojo/core/embedder",
- "//testing/gmock",
- "//testing/gtest",
- "//ui/aura",
- "//ui/aura:test_support",
- "//ui/base",
- "//ui/base:test_support",
- "//ui/base/ime",
- "//ui/base/mojo:lib",
- "//ui/events:events_base",
- "//ui/events:test_support",
- "//ui/gl:test_support",
- "//ui/touch_selection",
- "//ui/views",
- "//ui/views:test_support_internal",
- "//ui/wm",
- "//ui/wm/public",
- ]
-
- data_deps = [
- ":views_mus_tests_catalog_copy",
- "//services/ws/test_ws",
- ]
-
- if (is_win) {
- deps += [
- "//build/win:default_exe_manifest",
- "//third_party/iaccessible2",
- "//third_party/wtl",
- ]
- libs = [
- "imm32.lib",
- "oleacc.lib",
- "comctl32.lib",
- ]
- }
-}
-
-service_manifest("unittests_manifest") {
- name = "views_mus_unittests"
- source = "unittests_manifest.json"
-}
-
-service_manifest("interactive_ui_tests_manifest") {
- name = "views_mus_interactive_ui_tests"
- source = "interactive_ui_tests_manifest.json"
-}
-
-catalog("views_mus_tests_catalog") {
- testonly = true
-
- embedded_services = [
- ":unittests_manifest",
- ":interactive_ui_tests_manifest",
- ]
-
- standalone_services = [
- "//services/ws/test_ws:manifest",
- "//services/ws/ime/test_ime_driver:manifest",
- ]
-}
-
-copy("views_mus_tests_catalog_copy") {
- testonly = true
- sources = get_target_outputs(":views_mus_tests_catalog")
- outputs = [
- "${root_out_dir}/views_mus_tests_catalog.json",
- ]
- deps = [
- ":views_mus_tests_catalog",
- ]
-}
diff --git a/chromium/ui/views/mus/DEPS b/chromium/ui/views/mus/DEPS
index 6c5f22db116..72bd2b47cae 100644
--- a/chromium/ui/views/mus/DEPS
+++ b/chromium/ui/views/mus/DEPS
@@ -20,12 +20,3 @@ include_rules = [
"+ui/platform_window",
"+ui/wm",
]
-
-specific_include_rules = {
- "views_mus_test_suite.cc": [
- "+services/service_manager/background",
- ],
- "views_aura_mus_test_suite.cc": [
- "+services/service_manager/background",
- ],
-}
diff --git a/chromium/ui/views/mus/OWNERS b/chromium/ui/views/mus/OWNERS
index 3a73ee3f4a5..1b6d3c5e375 100644
--- a/chromium/ui/views/mus/OWNERS
+++ b/chromium/ui/views/mus/OWNERS
@@ -3,9 +3,3 @@ msw@chromium.org
sky@chromium.org
per-file ax_*=file://ui/accessibility/OWNERS
-
-per-file interactive_ui_tests_manifest.json=set noparent
-per-file interactive_ui_tests_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file unittests_manifest.json=set noparent
-per-file unittests_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/ui/views/mus/ax_remote_host_unittest.cc b/chromium/ui/views/mus/ax_remote_host_unittest.cc
index 934dcfe3ed5..0bcbf8e4e5f 100644
--- a/chromium/ui/views/mus/ax_remote_host_unittest.cc
+++ b/chromium/ui/views/mus/ax_remote_host_unittest.cc
@@ -26,7 +26,7 @@ namespace {
// Returns a well-known tree ID for the test widget.
const ui::AXTreeID& TestAXTreeID() {
static const base::NoDestructor<ui::AXTreeID> test_ax_tree_id(
- ui::AXTreeID::FromString("123"));
+ ui::AXTreeID::CreateNewAXTreeID());
return *test_ax_tree_id;
}
@@ -62,7 +62,7 @@ class TestAXHostService : public ax::mojom::AXHost {
const std::vector<ui::AXTreeUpdate>& updates,
const ui::AXEvent& event) override {
++event_count_;
- last_tree_id_ = ui::AXTreeID::FromString(tree_id);
+ last_tree_id_ = tree_id;
last_updates_ = updates;
last_event_ = event;
}
@@ -131,7 +131,7 @@ std::unique_ptr<Widget> CreateTestWidget() {
return widget;
}
-using AXRemoteHostTest = ViewsTestBase;
+using AXRemoteHostTest = ViewsTestWithDesktopNativeWidget;
TEST_F(AXRemoteHostTest, CreateRemote) {
TestAXHostService service(false /*automation_enabled*/);
diff --git a/chromium/ui/views/mus/ax_tree_source_mus.cc b/chromium/ui/views/mus/ax_tree_source_mus.cc
index 842a32f9969..f014f309950 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus.cc
+++ b/chromium/ui/views/mus/ax_tree_source_mus.cc
@@ -12,9 +12,8 @@
namespace views {
AXTreeSourceMus::AXTreeSourceMus(AXAuraObjWrapper* root,
- const ui::AXTreeID& tree_id) {
- Init(root, tree_id);
-}
+ const ui::AXTreeID& tree_id)
+ : AXTreeSourceViews(root, tree_id) {}
AXTreeSourceMus::~AXTreeSourceMus() = default;
diff --git a/chromium/ui/views/mus/ax_tree_source_mus.h b/chromium/ui/views/mus/ax_tree_source_mus.h
index a14d78ea673..9246bb5819c 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus.h
+++ b/chromium/ui/views/mus/ax_tree_source_mus.h
@@ -16,7 +16,7 @@ class AXAuraObjWrapper;
// This class exposes the views hierarchy as an accessibility tree permitting
// use with other accessibility classes. Only used for out-of-process views
// apps (e.g. Chrome OS shortcut_viewer app). The browser process uses
-// AXTreeSourceAura.
+// AXTreeSourceViews directly.
class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
public:
// |root| must outlive this object.
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 51f5cd2d57b..1f8320bf0bd 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
+++ b/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
@@ -31,6 +31,7 @@ class AXTreeSourceMusTest : public ViewsTestBase {
// testing::Test:
void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
ViewsTestBase::SetUp();
widget_ = std::make_unique<Widget>();
Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
@@ -51,7 +52,7 @@ class AXTreeSourceMusTest : public ViewsTestBase {
std::unique_ptr<Widget> widget_;
Label* label_ = nullptr; // Owned by views hierarchy.
- const ui::AXTreeID ax_tree_id_ = ui::AXTreeID::FromString("123");
+ const ui::AXTreeID ax_tree_id_ = ui::AXTreeID::CreateNewAXTreeID();
private:
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceMusTest);
diff --git a/chromium/ui/views/mus/clipboard_unittest.cc b/chromium/ui/views/mus/clipboard_unittest.cc
index a00f61588e4..6c91d1e7c11 100644
--- a/chromium/ui/views/mus/clipboard_unittest.cc
+++ b/chromium/ui/views/mus/clipboard_unittest.cc
@@ -4,16 +4,26 @@
#include "ui/base/mojo/clipboard_client.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/platform/platform_event_source.h"
-#include "ui/views/mus/mus_client.h"
-#include "ui/views/test/scoped_views_test_helper.h"
+#include "ui/views/test/views_interactive_ui_test_base.h"
namespace ui {
namespace {
-std::unique_ptr<views::ScopedViewsTestHelper> g_scoped_views_test_helper;
+views::ViewsTestBase* g_test_base = nullptr;
+
+// This class is necessary to allow the Mus version of ClipboardTest to
+// initialize itself as if it's a ViewsTestBase (which creates the MusClient and
+// does other necessary setup). TODO(crbug/917180): improve this.
+class ViewsTestBaseNoTest : public views::ViewsInteractiveUITestBase {
+ public:
+ ViewsTestBaseNoTest() = default;
+ ~ViewsTestBaseNoTest() override = default;
+
+ // views::ViewsInteractiveUITestBase:
+ void TestBody() override {}
+};
} // namespace
@@ -23,18 +33,28 @@ struct PlatformClipboardTraits {
}
static Clipboard* Create() {
- g_scoped_views_test_helper =
- std::make_unique<views::ScopedViewsTestHelper>();
- EXPECT_TRUE(views::MusClient::Exists());
+ g_test_base = new ViewsTestBaseNoTest();
+ g_test_base->SetUp();
+
return Clipboard::GetForCurrentThread();
}
static void Destroy(Clipboard* clipboard) {
- g_scoped_views_test_helper.reset();
+ g_test_base->TearDown();
+ g_test_base = nullptr;
+ }
+};
+
+class MusClipboardTestName {
+ public:
+ template <typename T>
+ static std::string GetName(int index) {
+ return "MusClipboardTest";
}
};
using TypesToTest = PlatformClipboardTraits;
+using NamesOfTypesToTest = MusClipboardTestName;
} // namespace ui
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 01b7f545742..a2126cd62bc 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -48,16 +48,16 @@ namespace {
class ClientSideNonClientFrameView : public NonClientFrameView,
public aura::WindowObserver {
public:
- explicit ClientSideNonClientFrameView(views::Widget* widget)
- : widget_(widget) {
+ explicit ClientSideNonClientFrameView(Widget* widget) : widget_(widget) {
// Not part of the accessibility node hierarchy because the window frame is
// provided by the window manager.
- GetViewAccessibility().OverrideIsIgnored(true);
+ if (MusClient::Get()->use_remote_accessibility_host())
+ GetViewAccessibility().OverrideIsIgnored(true);
// Initialize kTopViewInset to a default value. Further updates will come
// from Ash. This is necessary so that during app window creation,
// GetWindowBoundsForClientBounds() can calculate correctly.
- const auto& values = views::WindowManagerFrameValues::instance();
+ const auto& values = WindowManagerFrameValues::instance();
widget->GetNativeWindow()->SetProperty(aura::client::kTopViewInset,
widget->IsMaximized()
? values.maximized_insets.top()
@@ -95,7 +95,7 @@ class ClientSideNonClientFrameView : public NonClientFrameView,
return outset_bounds;
}
int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
- void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {
// The window manager provides the shape; do nothing.
}
void ResetWindowControls() override {
@@ -150,7 +150,7 @@ class ClientSideNonClientFrameView : public NonClientFrameView,
return widget_->GetNativeWindow()->GetRootWindow();
}
- views::Widget* widget_;
+ Widget* widget_;
ScopedObserver<aura::Window, aura::WindowObserver> observed_{this};
DISALLOW_COPY_AND_ASSIGN(ClientSideNonClientFrameView);
@@ -167,18 +167,9 @@ class NativeCursorManagerMus : public wm::NativeCursorManager {
// We ignore this entirely, as cursor are set on the client.
}
- void SetCursor(gfx::NativeCursor cursor,
+ void SetCursor(ui::Cursor cursor,
wm::NativeCursorManagerDelegate* delegate) override {
- ui::CursorData mojo_cursor;
- if (cursor.native_type() == ui::CursorType::kCustom) {
- mojo_cursor =
- ui::CursorData(cursor.GetHotspot(), {cursor.GetBitmap()},
- cursor.device_scale_factor(), base::TimeDelta());
- } else {
- mojo_cursor = ui::CursorData(cursor.native_type());
- }
-
- aura::WindowPortMus::Get(window_)->SetCursor(mojo_cursor);
+ aura::WindowPortMus::Get(window_)->SetCursor(cursor);
delegate->CommitCursor(cursor);
}
@@ -190,7 +181,7 @@ class NativeCursorManagerMus : public wm::NativeCursorManager {
SetCursor(delegate->GetCursor(), delegate);
} else {
aura::WindowPortMus::Get(window_)->SetCursor(
- ui::CursorData(ui::CursorType::kNone));
+ ui::Cursor(ui::CursorType::kNone));
}
}
@@ -228,54 +219,6 @@ 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
@@ -394,14 +337,6 @@ float DesktopWindowTreeHostMus::GetScaleFactor() const {
.device_scale_factor();
}
-void DesktopWindowTreeHostMus::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) {
- // Do not use ConvertRectToPixel, enclosing rects cause problems.
- const gfx::Rect rect(
- gfx::ScaleToFlooredPoint(bounds_in_dip.origin(), GetScaleFactor()),
- gfx::ScaleToCeiledSize(bounds_in_dip.size(), GetScaleFactor()));
- SetBoundsInPixels(rect, viz::LocalSurfaceIdAllocation());
-}
-
bool DesktopWindowTreeHostMus::IsWaitingForRestoreToComplete() const {
return window_tree_host_window_observer_->is_waiting_for_restore();
}
@@ -410,9 +345,8 @@ bool DesktopWindowTreeHostMus::ShouldSendClientAreaToServer() const {
if (!auto_update_client_area_)
return false;
- using WIP = views::Widget::InitParams;
- const WIP::Type type = desktop_native_widget_aura_->widget_type();
- return type == WIP::TYPE_WINDOW || type == WIP::TYPE_PANEL;
+ return desktop_native_widget_aura_->widget_type() ==
+ Widget::InitParams::TYPE_WINDOW;
}
void DesktopWindowTreeHostMus::RestoreToPreminimizedState() {
@@ -502,15 +436,13 @@ void DesktopWindowTreeHostMus::Init(const Widget::InitParams& params) {
if (!params.accept_events)
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);
+ params.opacity == Widget::InitParams::OPAQUE_WINDOW);
}
void DesktopWindowTreeHostMus::OnNativeWidgetCreated(
@@ -519,7 +451,7 @@ void DesktopWindowTreeHostMus::OnNativeWidgetCreated(
parent_ = static_cast<DesktopWindowTreeHostMus*>(params.parent->GetHost());
parent_->children_.insert(this);
}
- native_widget_delegate_->OnNativeWidgetCreated(true);
+ native_widget_delegate_->OnNativeWidgetCreated();
}
void DesktopWindowTreeHostMus::OnActiveWindowChanged(bool active) {
@@ -553,10 +485,12 @@ void DesktopWindowTreeHostMus::OnWidgetInitDone() {
// These views are not part of the accessibility node hierarchy because the
// window frame is provided by the window manager.
Widget* widget = native_widget_delegate_->AsWidget();
- if (widget->non_client_view())
- widget->non_client_view()->GetViewAccessibility().OverrideIsIgnored(true);
- if (widget->client_view())
- widget->client_view()->GetViewAccessibility().OverrideIsIgnored(true);
+ if (MusClient::Get()->use_remote_accessibility_host()) {
+ if (widget->non_client_view())
+ widget->non_client_view()->GetViewAccessibility().OverrideIsIgnored(true);
+ if (widget->client_view())
+ widget->client_view()->GetViewAccessibility().OverrideIsIgnored(true);
+ }
MusClient::Get()->OnWidgetInitDone(widget);
}
@@ -902,14 +836,6 @@ 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();
-
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
ws::mojom::MoveLoopSource mus_source =
@@ -924,8 +850,8 @@ Widget::MoveLoopResult DesktopWindowTreeHostMus::RunMoveLoop(
gfx::Point cursor_location = window()->GetBoundsInScreen().origin() +
gfx::ToFlooredVector2d(drag_offset);
WindowTreeHostMus::PerformWindowMove(
- mus_source, cursor_location,
- base::Bind(OnMoveLoopEnd, &success, run_loop.QuitClosure()));
+ content_window(), mus_source, cursor_location,
+ base::BindOnce(&OnMoveLoopEnd, &success, run_loop.QuitClosure()));
run_loop.Run();
@@ -976,6 +902,11 @@ void DesktopWindowTreeHostMus::SetOpacity(float opacity) {
WindowTreeHostMus::SetOpacity(opacity);
}
+void DesktopWindowTreeHostMus::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
+ window()->SetProperty(aura::client::kAspectRatio,
+ new gfx::SizeF(aspect_ratio));
+}
+
void DesktopWindowTreeHostMus::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
NativeWidgetAura::AssignIconToAuraWindow(window(), window_icon, app_icon);
@@ -1023,6 +954,14 @@ bool DesktopWindowTreeHostMus::ShouldCreateVisibilityController() const {
return false;
}
+void DesktopWindowTreeHostMus::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) {
+ // Do not use ConvertRectToPixel, enclosing rects cause problems.
+ const gfx::Rect rect(
+ gfx::ScaleToFlooredPoint(bounds_in_dip.origin(), GetScaleFactor()),
+ gfx::ScaleToCeiledSize(bounds_in_dip.size(), GetScaleFactor()));
+ SetBoundsInPixels(rect, viz::LocalSurfaceIdAllocation());
+}
+
void DesktopWindowTreeHostMus::OnWindowManagerFrameValuesChanged() {
NonClientView* non_client_view =
native_widget_delegate_->AsWidget()->non_client_view();
@@ -1115,7 +1054,7 @@ void DesktopWindowTreeHostMus::SetBoundsInPixels(
local_surface_id_allocation);
}
-void DesktopWindowTreeHostMus::OnViewBoundsChanged(views::View* observed_view) {
+void DesktopWindowTreeHostMus::OnViewBoundsChanged(View* observed_view) {
DCHECK_EQ(
observed_view,
native_widget_delegate_->AsWidget()->non_client_view()->client_view());
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus.h b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
index 6d61f260e33..9daf24b397a 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.h
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
@@ -59,8 +59,6 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
// Helper function to get the scale factor.
float GetScaleFactor() const;
- void SetBoundsInDIP(const gfx::Rect& bounds_in_dip);
-
// Returns true if the client area should be set on this.
bool ShouldSendClientAreaToServer() const;
@@ -138,7 +136,7 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
void SetFullscreen(bool fullscreen) override;
bool IsFullscreen() const override;
void SetOpacity(float opacity) override;
- void SetAspectRatio(const gfx::SizeF& aspect_ratio) override {}
+ void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) override;
void InitModalType(ui::ModalType modal_type) override;
@@ -149,6 +147,7 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
bool ShouldUpdateWindowTransparency() const override;
bool ShouldUseDesktopNativeCursorManager() const override;
bool ShouldCreateVisibilityController() const override;
+ void SetBoundsInDIP(const gfx::Rect& bounds_in_dip) override;
// MusClientObserver:
void OnWindowManagerFrameValuesChanged() override;
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 f5c2ba853eb..d78253d668f 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
@@ -7,6 +7,7 @@
#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-test-utils.h"
#include "services/ws/test_ws/test_ws.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
@@ -30,9 +31,11 @@
#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/ax_remote_host.h"
#include "ui/views/mus/mus_client.h"
#include "ui/views/mus/mus_client_test_api.h"
#include "ui/views/mus/screen_mus.h"
+#include "ui/views/test/native_widget_factory.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -45,9 +48,14 @@ namespace views {
class DesktopWindowTreeHostMusTest : public ViewsTestBase,
public WidgetObserver {
public:
- DesktopWindowTreeHostMusTest()
- : widget_activated_(nullptr), widget_deactivated_(nullptr) {}
- ~DesktopWindowTreeHostMusTest() override {}
+ DesktopWindowTreeHostMusTest() = default;
+ ~DesktopWindowTreeHostMusTest() override = default;
+
+ // ViewsTestBase:
+ void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+ ViewsTestBase::SetUp();
+ }
// Creates a test widget. Takes ownership of |delegate|.
std::unique_ptr<Widget> CreateWidget(WidgetDelegate* delegate = nullptr,
@@ -77,8 +85,8 @@ class DesktopWindowTreeHostMusTest : public ViewsTestBase,
}
}
- Widget* widget_activated_;
- Widget* widget_deactivated_;
+ Widget* widget_activated_ = nullptr;
+ Widget* widget_deactivated_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostMusTest);
};
@@ -406,7 +414,7 @@ TEST_F(DesktopWindowTreeHostMusTest, CreateFullscreenWidget) {
for (auto widget_type : kWidgetTypes) {
Widget widget;
- Widget::InitParams params(widget_type);
+ Widget::InitParams params = CreateParams(widget_type);
params.show_state = ui::SHOW_STATE_FULLSCREEN;
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(params);
@@ -580,6 +588,9 @@ TEST_F(DesktopWindowTreeHostMusTest, WindowTitle) {
}
TEST_F(DesktopWindowTreeHostMusTest, Accessibility) {
+ // Pretend we're using the remote AX service, like shortcut_viewer.
+ MusClientTestApi::SetAXRemoteHost(std::make_unique<AXRemoteHost>());
+
std::unique_ptr<Widget> widget = CreateWidget();
// Widget frame views do not participate in accessibility node hierarchy
// because the frame is provided by the window manager.
@@ -912,4 +923,41 @@ TEST_F(DesktopWindowTreeHostMusTest, TransientChildMatchesParentVisibility) {
transient_child->RemoveObserver(&observer);
}
+// DesktopWindowTreeHostMusTest with --force-device-scale-factor=1.25.
+class DesktopWindowTreeHostMusTestFractionalDPI
+ : public DesktopWindowTreeHostMusTest {
+ public:
+ DesktopWindowTreeHostMusTestFractionalDPI() = default;
+ ~DesktopWindowTreeHostMusTestFractionalDPI() override = default;
+
+ // DesktopWindowTreeHostMusTest:
+ void SetUp() override {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kForceDeviceScaleFactor, "1.25");
+ DesktopWindowTreeHostMusTest::SetUp();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostMusTestFractionalDPI);
+};
+
+TEST_F(DesktopWindowTreeHostMusTestFractionalDPI,
+ SetBoundsInDipWithFractionalScale) {
+ std::unique_ptr<Widget> widget(CreateWidget());
+ // These numbers are carefully chosen such that if enclosing rect is used
+ // the pixel values differ between the two. The WindowServcie assumes ceiling
+ // is used on the size, which is not impacted by the location.
+ const gfx::Rect bounds1(408, 48, 339, 296);
+ const int expected_pixel_height =
+ gfx::ScaleToCeiledSize(bounds1.size(), 1.25f).height();
+ widget->SetBounds(bounds1);
+ EXPECT_EQ(expected_pixel_height,
+ widget->GetNativeWindow()->GetHost()->GetBoundsInPixels().height());
+
+ const gfx::Rect bounds2(gfx::Point(408, 49), bounds1.size());
+ widget->SetBounds(bounds2);
+ EXPECT_EQ(expected_pixel_height,
+ widget->GetNativeWindow()->GetHost()->GetBoundsInPixels().height());
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/drag_interactive_uitest.cc b/chromium/ui/views/mus/drag_interactive_uitest.cc
index 92dc07d7a7d..822de294480 100644
--- a/chromium/ui/views/mus/drag_interactive_uitest.cc
+++ b/chromium/ui/views/mus/drag_interactive_uitest.cc
@@ -15,7 +15,7 @@
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/views/mus/mus_client.h"
-#include "ui/views/test/widget_test.h"
+#include "ui/views/test/views_interactive_ui_test_base.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/widget.h"
@@ -60,7 +60,7 @@ class TargetView : public views::View {
// views::View overrides:
bool GetDropFormats(
int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) override {
+ std::set<ui::ClipboardFormatType>* format_types) override {
*formats = ui::OSExchangeData::STRING;
return true;
}
@@ -108,7 +108,7 @@ std::unique_ptr<ui::MouseEvent> CreateMouseUpEvent(int x, int y) {
} // namespace
-using DragTestInteractive = WidgetTest;
+using DragTestInteractive = ViewsInteractiveUITestBase;
// Dispatch of events is asynchronous so most of DragTestInteractive.DragTest
// consists of callback functions which will perform an action after the
@@ -151,7 +151,9 @@ TEST_F(DragTestInteractive, DragTest) {
ws::mojom::EventInjectorPtr event_injector;
MusClient::Get()->window_tree_client()->connector()->BindInterface(
ws::mojom::kServiceName, &event_injector);
- Widget* source_widget = CreateTopLevelFramelessPlatformWidget();
+
+ Widget* source_widget = new Widget;
+ source_widget->Init(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
View* source_view = new DraggableView;
source_widget->SetContentsView(source_view);
source_widget->Show();
@@ -161,7 +163,9 @@ TEST_F(DragTestInteractive, DragTest) {
source_widget->SetBounds(gfx::Rect(0, 0, 20, 20));
ASSERT_TRUE(source_waiter.Wait());
- Widget* target_widget = CreateTopLevelFramelessPlatformWidget();
+ Widget* target_widget = new Widget;
+ target_widget->Init(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
+
TargetView* target_view = new TargetView;
target_widget->SetContentsView(target_view);
target_widget->Show();
diff --git a/chromium/ui/views/mus/interactive_ui_tests_mus.cc b/chromium/ui/views/mus/interactive_ui_tests_mus.cc
deleted file mode 100644
index 5bea8092bb4..00000000000
--- a/chromium/ui/views/mus/interactive_ui_tests_mus.cc
+++ /dev/null
@@ -1,9 +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/views_mus_test_suite.h"
-
-int main(int argc, char** argv) {
- return views::ViewsMusTestSuite(argc, argv).RunTestsSerially();
-}
diff --git a/chromium/ui/views/mus/mus_client.cc b/chromium/ui/views/mus/mus_client.cc
index 447610137b9..56c57cf37df 100644
--- a/chromium/ui/views/mus/mus_client.cc
+++ b/chromium/ui/views/mus/mus_client.cc
@@ -43,7 +43,6 @@
"Window type constants must match")
WINDOW_TYPES_MATCH(WINDOW);
-WINDOW_TYPES_MATCH(PANEL);
WINDOW_TYPES_MATCH(WINDOW_FRAMELESS);
WINDOW_TYPES_MATCH(CONTROL);
WINDOW_TYPES_MATCH(POPUP);
@@ -176,11 +175,10 @@ bool MusClient::ShouldCreateDesktopNativeWidgetAura(
// static
bool MusClient::ShouldMakeWidgetWindowsTranslucent(
const Widget::InitParams& params) {
- // |TYPE_WINDOW| and |TYPE_PANEL| are forced to translucent so that the
- // window manager can draw the client decorations.
+ // |TYPE_WINDOW| is forced to translucent so that the window manager
+ // can draw the client decorations.
return params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW ||
- params.type == Widget::InitParams::TYPE_WINDOW ||
- params.type == Widget::InitParams::TYPE_PANEL;
+ params.type == Widget::InitParams::TYPE_WINDOW;
}
// static
@@ -218,7 +216,7 @@ MusClient::ConfigurePropertiesFromParams(
mojo::ConvertTo<TransportType>(
static_cast<PrimitiveType>(init_params.keep_on_top));
- properties[WindowManager::kRemoveStandardFrame_InitProperty] =
+ properties[WindowManager::kClientProvidesFrame_InitProperty] =
mojo::ConvertTo<TransportType>(init_params.remove_standard_frame);
if (init_params.corner_radius) {
diff --git a/chromium/ui/views/mus/mus_client.h b/chromium/ui/views/mus/mus_client.h
index 143637135ba..2de12412f99 100644
--- a/chromium/ui/views/mus/mus_client.h
+++ b/chromium/ui/views/mus/mus_client.h
@@ -113,6 +113,8 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
return property_converter_.get();
}
+ bool use_remote_accessibility_host() const { return !!ax_remote_host_; }
+
aura::WindowTreeClient* window_tree_client() { return window_tree_client_; }
// Creates DesktopNativeWidgetAura with DesktopWindowTreeHostMus. This is
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc b/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
index 30db5c39f9a..616e943d09a 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
+++ b/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
@@ -46,10 +46,16 @@ class RemoteViewHostTest : public aura::test::AuraTestBase {
// aura::test::AuraTestBase
void SetUp() override {
+ env_ = aura::Env::CreateInstance();
EnableMusWithTestWindowTree();
AuraTestBase::SetUp();
}
+ void TearDown() override {
+ AuraTestBase::TearDown();
+ env_.reset();
+ }
+
// Creates a widget to host |contents|.
std::unique_ptr<views::Widget> CreateTestWidget(views::View* contents) {
std::unique_ptr<views::Widget> widget = std::make_unique<views::Widget>();
@@ -77,6 +83,8 @@ class RemoteViewHostTest : public aura::test::AuraTestBase {
}
private:
+ std::unique_ptr<aura::Env> env_;
+
DISALLOW_COPY_AND_ASSIGN(RemoteViewHostTest);
};
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider.cc b/chromium/ui/views/mus/remote_view/remote_view_provider.cc
index 12286cd26af..ea0cdadaf38 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_provider.cc
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider.cc
@@ -15,6 +15,7 @@
#include "ui/aura/window_observer.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/mus/mus_client.h"
+#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
namespace views {
@@ -133,6 +134,8 @@ void RemoteViewProvider::OnEmbedTokenAvailable(
void RemoteViewProvider::OnEmbed(aura::Window* window) {
DCHECK(embedded_);
+ screen_position_client_ =
+ std::make_unique<DesktopScreenPositionClient>(window);
embedding_window_observer_ = std::make_unique<EmbeddingWindowObserver>(
window, base::BindRepeating(&RemoteViewProvider::OnEmbeddingWindowResized,
base::Unretained(this)));
@@ -144,6 +147,7 @@ void RemoteViewProvider::OnEmbed(aura::Window* window) {
}
void RemoteViewProvider::OnUnembed() {
+ screen_position_client_.reset();
embedding_window_observer_.reset();
embed_root_.reset();
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider.h b/chromium/ui/views/mus/remote_view/remote_view_provider.h
index 9717d5f8a76..ac3722e36ff 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_provider.h
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider.h
@@ -24,6 +24,8 @@ class Size;
namespace views {
+class DesktopScreenPositionClient;
+
namespace test {
class RemoteViewProviderTestApi;
}
@@ -90,6 +92,10 @@ class RemoteViewProvider : public aura::EmbedRootDelegate {
// Observes the embeddding window provided by embedder.
std::unique_ptr<EmbeddingWindowObserver> embedding_window_observer_;
+ // Installed on the WindowTreeHost's window. Installing this makes
+ // aura::Window::GetBoundsInScreen() work for any descendants.
+ std::unique_ptr<DesktopScreenPositionClient> screen_position_client_;
+
DISALLOW_COPY_AND_ASSIGN(RemoteViewProvider);
};
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc b/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
index f396829094d..0cd4fcacfe5 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
@@ -15,6 +15,7 @@
#include "ui/aura/test/mus/test_window_tree.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tracker.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/mus/remote_view/remote_view_provider_test_api.h"
@@ -27,6 +28,7 @@ class RemoteViewProviderTest : public aura::test::AuraTestBase {
// aura::test::AuraTestBase
void SetUp() override {
+ env_ = aura::Env::CreateInstance();
EnableMusWithTestWindowTree();
AuraTestBase::SetUp();
@@ -109,6 +111,7 @@ class RemoteViewProviderTest : public aura::test::AuraTestBase {
}
protected:
+ std::unique_ptr<aura::Env> env_;
std::unique_ptr<aura::Window> embedded_;
std::unique_ptr<RemoteViewProvider> provider_;
@@ -171,4 +174,20 @@ TEST_F(RemoteViewProviderTest, EmbedAgain) {
ASSERT_TRUE(new_embedder);
}
+TEST_F(RemoteViewProviderTest, ScreenBounds) {
+ aura::Window* embedder = SimulateEmbed();
+ ASSERT_TRUE(embedder);
+
+ const viz::LocalSurfaceId server_changed_local_surface_id(
+ 1, base::UnguessableToken::Create());
+ aura::Window* root_window = embedded_->GetRootWindow();
+ ASSERT_TRUE(root_window);
+ const gfx::Rect root_bounds(101, 102, 100, 50);
+ window_tree_client()->OnWindowBoundsChanged(
+ aura::WindowMus::Get(root_window)->server_id(), gfx::Rect(), root_bounds,
+ server_changed_local_surface_id);
+ EXPECT_EQ(root_bounds, root_window->GetHost()->GetBoundsInPixels());
+ EXPECT_EQ(root_bounds.origin(), root_window->GetBoundsInScreen().origin());
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/run_all_unittests_mus.cc b/chromium/ui/views/mus/run_all_unittests_mus.cc
deleted file mode 100644
index 49d9aaf8371..00000000000
--- a/chromium/ui/views/mus/run_all_unittests_mus.cc
+++ /dev/null
@@ -1,9 +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/views_mus_test_suite.h"
-
-int main(int argc, char** argv) {
- return views::ViewsMusTestSuite(argc, argv).RunTests();
-}
diff --git a/chromium/ui/views/mus/screen_mus_unittest.cc b/chromium/ui/views/mus/screen_mus_unittest.cc
index e27751a1494..28b0263967d 100644
--- a/chromium/ui/views/mus/screen_mus_unittest.cc
+++ b/chromium/ui/views/mus/screen_mus_unittest.cc
@@ -6,10 +6,9 @@
#include "base/command_line.h"
#include "base/test/scoped_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/display_switches.h"
#include "ui/display/screen.h"
-#include "ui/views/test/scoped_views_test_helper.h"
+#include "ui/views/test/views_test_base.h"
namespace views {
namespace {
@@ -27,34 +26,7 @@ std::vector<ws::mojom::WsDisplayPtr> ConvertDisplayToWsDisplays(
return results;
}
-TEST(ScreenMusScaleFactorTest, ConsistentDisplayInHighDPI) {
- base::test::ScopedTaskEnvironment task_environment(
- base::test::ScopedTaskEnvironment::MainThreadType::UI);
- // Must be set before |test_helper| is constructed.
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kForceDeviceScaleFactor, "2");
- ScopedViewsTestHelper test_helper;
- display::Screen* screen = display::Screen::GetScreen();
- std::vector<display::Display> displays = screen->GetAllDisplays();
- ASSERT_FALSE(displays.empty());
- for (const display::Display& display : displays) {
- EXPECT_EQ(2.f, display.device_scale_factor());
- EXPECT_EQ(display.work_area(), display.bounds());
- }
-}
-
-class ScreenMusTest : public testing::Test {
- public:
- ScreenMusTest() = default;
- ~ScreenMusTest() override = default;
-
- private:
- base::test::ScopedTaskEnvironment task_environment_{
- base::test::ScopedTaskEnvironment::MainThreadType::UI};
- ScopedViewsTestHelper test_helper_;
-
- DISALLOW_COPY_AND_ASSIGN(ScreenMusTest);
-};
+using ScreenMusTest = ViewsTestWithDesktopNativeWidget;
TEST_F(ScreenMusTest, PrimaryChangedToExisting) {
ScreenMus* screen = static_cast<ScreenMus*>(display::Screen::GetScreen());
@@ -123,5 +95,30 @@ TEST_F(ScreenMusTest, SetDisplayForNewWindows) {
EXPECT_EQ(kDisplayId1, screen->GetDisplayForNewWindows().id());
}
+class ScreenMusScaleFactorTest : public ScreenMusTest {
+ public:
+ ScreenMusScaleFactorTest() = default;
+ ~ScreenMusScaleFactorTest() override = default;
+
+ void SetUp() override {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kForceDeviceScaleFactor, "2");
+ ScreenMusTest::SetUp();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScreenMusScaleFactorTest);
+};
+
+TEST_F(ScreenMusScaleFactorTest, ConsistentDisplayInHighDPI) {
+ display::Screen* screen = display::Screen::GetScreen();
+ std::vector<display::Display> displays = screen->GetAllDisplays();
+ ASSERT_FALSE(displays.empty());
+ for (const display::Display& display : displays) {
+ EXPECT_EQ(2.f, display.device_scale_factor());
+ EXPECT_EQ(display.work_area(), display.bounds());
+ }
+}
+
} // namespace
} // namespace views
diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc
deleted file mode 100644
index d5713e1460a..00000000000
--- a/chromium/ui/views/mus/views_mus_test_suite.cc
+++ /dev/null
@@ -1,263 +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/views_mus_test_suite.h"
-
-#include <memory>
-#include <string>
-
-#include "base/base_switches.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/simple_thread.h"
-#include "mojo/core/embedder/embedder.h"
-#include "mojo/core/embedder/scoped_ipc_support.h"
-#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"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/env.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
-#include "ui/aura/test/mus/input_method_mus_test_api.h"
-#include "ui/aura/window.h"
-#include "ui/base/ui_base_features.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/compositor/test/fake_context_factory.h"
-#include "ui/gl/gl_switches.h"
-#include "ui/views/mus/desktop_window_tree_host_mus.h"
-#include "ui/views/mus/mus_client.h"
-#include "ui/views/test/platform_test_helper.h"
-#include "ui/views/test/views_test_helper_aura.h"
-#include "ui/views/views_delegate.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-
-namespace views {
-namespace {
-
-const base::FilePath::CharType kCatalogFilename[] =
- FILE_PATH_LITERAL("views_mus_tests_catalog.json");
-
-void EnsureCommandLineSwitch(const std::string& name) {
- base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
- if (!cmd_line->HasSwitch(name))
- cmd_line->AppendSwitch(name);
-}
-
-class DefaultService : public service_manager::Service {
- public:
- DefaultService() {}
- ~DefaultService() override {}
-
- // service_manager::Service:
- void OnBindInterface(const service_manager::BindSourceInfo& source_info,
- const std::string& interface_name,
- mojo::ScopedMessagePipeHandle interface_pipe) override {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DefaultService);
-};
-
-class ServiceManagerConnection {
- public:
- ServiceManagerConnection()
- : thread_("Persistent service_manager connections") {
- catalog::Catalog::LoadDefaultCatalogManifest(
- base::FilePath(kCatalogFilename));
- base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::Thread::Options options;
- thread_.StartWithOptions(options);
- thread_.task_runner()->PostTask(
- FROM_HERE,
- base::BindOnce(
- &ServiceManagerConnection::SetUpConnectionsOnBackgroundThread,
- base::Unretained(this), &wait));
- wait.Wait();
- }
-
- ~ServiceManagerConnection() {
- base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- thread_.task_runner()->PostTask(
- FROM_HERE,
- base::BindOnce(
- &ServiceManagerConnection::TearDownConnectionsOnBackgroundThread,
- base::Unretained(this), &wait));
- wait.Wait();
- }
-
- std::unique_ptr<MusClient> CreateMusClient() {
- MusClient::InitParams params;
- params.connector = GetConnector();
- params.identity = service_manager_identity_;
- return std::make_unique<MusClient>(params);
- }
-
- private:
- service_manager::Connector* GetConnector() {
- service_manager_connector_.reset();
- base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- thread_.task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&ServiceManagerConnection::CloneConnector,
- base::Unretained(this), &wait));
- wait.Wait();
- DCHECK(service_manager_connector_);
- return service_manager_connector_.get();
- }
-
- void CloneConnector(base::WaitableEvent* wait) {
- service_manager_connector_ = context_->connector()->Clone();
- wait->Signal();
- }
-
- void SetUpConnectionsOnBackgroundThread(base::WaitableEvent* wait) {
- background_service_manager_ =
- std::make_unique<service_manager::BackgroundServiceManager>(nullptr,
- nullptr);
- service_manager::mojom::ServicePtr service;
- context_ = std::make_unique<service_manager::ServiceContext>(
- std::make_unique<DefaultService>(), mojo::MakeRequest(&service));
- background_service_manager_->RegisterService(
- 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();
- wait->Signal();
- }
-
- void TearDownConnectionsOnBackgroundThread(base::WaitableEvent* wait) {
- context_.reset();
- background_service_manager_.reset();
- wait->Signal();
- }
-
- // Returns the name of the test executable, e.g. "views_mus_unittests".
- std::string GetTestName() {
- base::FilePath executable = base::CommandLine::ForCurrentProcess()
- ->GetProgram()
- .BaseName()
- .RemoveExtension();
- return executable.MaybeAsASCII();
- }
-
- base::Thread thread_;
- std::unique_ptr<service_manager::BackgroundServiceManager>
- background_service_manager_;
- std::unique_ptr<service_manager::ServiceContext> context_;
- std::unique_ptr<service_manager::Connector> service_manager_connector_;
- service_manager::Identity service_manager_identity_;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceManagerConnection);
-};
-
-class PlatformTestHelperMus : public PlatformTestHelper {
- public:
- PlatformTestHelperMus() {
- mus_client_ = service_manager_connection_.CreateMusClient();
- ViewsDelegate::GetInstance()->set_native_widget_factory(base::Bind(
- &PlatformTestHelperMus::CreateNativeWidget, base::Unretained(this)));
- }
- ~PlatformTestHelperMus() override {}
-
- // PlatformTestHelper:
- void OnTestHelperCreated(ViewsTestHelper* helper) override {
- static_cast<ViewsTestHelperAura*>(helper)->EnableMusWithWindowTreeClient(
- mus_client_->window_tree_client());
- }
- void SimulateNativeDestroy(Widget* widget) override {
- aura::WindowTreeHostMus* window_tree_host =
- static_cast<aura::WindowTreeHostMus*>(
- widget->GetNativeView()->GetHost());
- static_cast<aura::WindowTreeClientDelegate*>(mus_client_.get())
- ->OnEmbedRootDestroyed(window_tree_host);
- }
-
- void InitializeContextFactory(
- ui::ContextFactory** context_factory,
- ui::ContextFactoryPrivate** context_factory_private) override {
- *context_factory = &context_factory_;
- *context_factory_private = nullptr;
- }
-
- private:
- NativeWidget* CreateNativeWidget(const Widget::InitParams& init_params,
- internal::NativeWidgetDelegate* delegate) {
- NativeWidget* native_widget =
- mus_client_->CreateNativeWidget(init_params, delegate);
- if (!native_widget)
- return nullptr;
-
- // Disable sending KeyEvents to IME as tests aren't set up to wait for an
- // ack (and tests run concurrently).
- aura::WindowTreeHostMus* window_tree_host_mus =
- static_cast<aura::WindowTreeHostMus*>(
- static_cast<DesktopNativeWidgetAura*>(native_widget)->host());
- aura::InputMethodMusTestApi::Disable(window_tree_host_mus->input_method());
- return native_widget;
- }
-
- ServiceManagerConnection service_manager_connection_;
- std::unique_ptr<MusClient> mus_client_;
- ui::FakeContextFactory context_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformTestHelperMus);
-};
-
-std::unique_ptr<PlatformTestHelper> CreatePlatformTestHelper() {
- return std::make_unique<PlatformTestHelperMus>();
-}
-
-} // namespace
-
-ViewsMusTestSuite::ViewsMusTestSuite(int argc, char** argv)
- : ViewsTestSuite(argc, argv), ipc_thread_("IPC thread") {}
-
-ViewsMusTestSuite::~ViewsMusTestSuite() {}
-
-void ViewsMusTestSuite::Initialize() {
- PlatformTestHelper::SetIsMus();
- // Let other services know that we're running in tests. Do this with a
- // command line flag to avoid making blocking calls to other processes for
- // setup for tests (e.g. to unlock the screen in the window manager).
- EnsureCommandLineSwitch(ws::switches::kUseTestConfig);
-
- EnsureCommandLineSwitch(switches::kOverrideUseSoftwareGLForTests);
-
- ViewsTestSuite::Initialize();
-
- // NOTE: this has to be after ViewsTestSuite::Initialize() as
- // TestSuite::Initialize() resets kEnableFeatures and the command line.
- feature_list_.InitAndEnableFeature(features::kMash);
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kEnableFeatures, features::kMash.name);
-
- PlatformTestHelper::set_factory(base::Bind(&CreatePlatformTestHelper));
-
- mojo::core::Init();
- ipc_thread_.StartWithOptions(
- base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
- ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
- ipc_thread_.task_runner(),
- mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
-}
-
-void ViewsMusTestSuite::InitializeEnv() {
- env_ = aura::Env::CreateInstance(aura::Env::Mode::MUS);
-}
-
-void ViewsMusTestSuite::DestroyEnv() {
- env_.reset();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/mus/views_mus_test_suite.h b/chromium/ui/views/mus/views_mus_test_suite.h
deleted file mode 100644
index 8490ab91912..00000000000
--- a/chromium/ui/views/mus/views_mus_test_suite.h
+++ /dev/null
@@ -1,46 +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_VIEWS_MUS_TEST_SUITE_H_
-#define UI_VIEWS_MUS_VIEWS_MUS_TEST_SUITE_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/threading/thread.h"
-#include "ui/views/views_test_suite.h"
-
-namespace mojo {
-namespace core {
-class ScopedIPCSupport;
-}
-} // namespace mojo
-
-namespace views {
-
-class ViewsMusTestSuite : public ViewsTestSuite {
- public:
- ViewsMusTestSuite(int argc, char** argv);
- ~ViewsMusTestSuite() override;
-
- private:
- // ViewsTestSuite:
- void Initialize() override;
- void InitializeEnv() override;
- void DestroyEnv() override;
-
- base::Thread ipc_thread_;
- std::unique_ptr<mojo::core::ScopedIPCSupport> ipc_support_;
-
- base::test::ScopedFeatureList feature_list_;
-
- std::unique_ptr<aura::Env> env_;
-
- DISALLOW_COPY_AND_ASSIGN(ViewsMusTestSuite);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_MUS_VIEWS_MUS_TEST_SUITE_H_
diff --git a/chromium/ui/views/mus/window_manager_constants_converters.cc b/chromium/ui/views/mus/window_manager_constants_converters.cc
index 08d927dc013..6e15c03a3d0 100644
--- a/chromium/ui/views/mus/window_manager_constants_converters.cc
+++ b/chromium/ui/views/mus/window_manager_constants_converters.cc
@@ -13,8 +13,6 @@ TypeConverter<ws::mojom::WindowType, views::Widget::InitParams::Type>::Convert(
switch (type) {
case views::Widget::InitParams::TYPE_WINDOW:
return ws::mojom::WindowType::WINDOW;
- case views::Widget::InitParams::TYPE_PANEL:
- return ws::mojom::WindowType::PANEL;
case views::Widget::InitParams::TYPE_WINDOW_FRAMELESS:
return ws::mojom::WindowType::WINDOW_FRAMELESS;
case views::Widget::InitParams::TYPE_CONTROL:
diff --git a/chromium/ui/views/painter.cc b/chromium/ui/views/painter.cc
index da297c1a02b..b9ce986a24f 100644
--- a/chromium/ui/views/painter.cc
+++ b/chromium/ui/views/painter.cc
@@ -99,40 +99,6 @@ void SolidRoundRectPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
}
}
-// DashedFocusPainter ----------------------------------------------------------
-
-class DashedFocusPainter : public Painter {
- public:
- explicit DashedFocusPainter(const gfx::Insets& insets);
- ~DashedFocusPainter() override;
-
- // Painter:
- gfx::Size GetMinimumSize() const override;
- void Paint(gfx::Canvas* canvas, const gfx::Size& size) override;
-
- private:
- const gfx::Insets insets_;
-
- DISALLOW_COPY_AND_ASSIGN(DashedFocusPainter);
-};
-
-DashedFocusPainter::DashedFocusPainter(const gfx::Insets& insets)
- : insets_(insets) {
-}
-
-DashedFocusPainter::~DashedFocusPainter() {
-}
-
-gfx::Size DashedFocusPainter::GetMinimumSize() const {
- return gfx::Size();
-}
-
-void DashedFocusPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
- gfx::Rect rect(size);
- rect.Inset(insets_);
- canvas->DrawFocusRect(rect);
-}
-
// SolidFocusPainter -----------------------------------------------------------
class SolidFocusPainter : public Painter {
@@ -313,17 +279,6 @@ std::unique_ptr<Painter> Painter::CreateImageGridPainter(
}
// static
-std::unique_ptr<Painter> Painter::CreateDashedFocusPainter() {
- return std::make_unique<DashedFocusPainter>(gfx::Insets());
-}
-
-// static
-std::unique_ptr<Painter> Painter::CreateDashedFocusPainterWithInsets(
- const gfx::Insets& insets) {
- return std::make_unique<DashedFocusPainter>(insets);
-}
-
-// static
std::unique_ptr<Painter> Painter::CreateSolidFocusPainter(
SkColor color,
const gfx::Insets& insets) {
diff --git a/chromium/ui/views/painter.h b/chromium/ui/views/painter.h
index 984348ee13a..66af15a0c10 100644
--- a/chromium/ui/views/painter.h
+++ b/chromium/ui/views/painter.h
@@ -86,10 +86,6 @@ class VIEWS_EXPORT Painter {
// Top-Left/Top/Top-Right/Left/[Center]/Right/Bottom-Left/Bottom/Bottom-Right.
static std::unique_ptr<Painter> CreateImageGridPainter(const int image_ids[]);
- // Factory methods for creating painters intended for rendering focus.
- static std::unique_ptr<Painter> CreateDashedFocusPainter();
- static std::unique_ptr<Painter> CreateDashedFocusPainterWithInsets(
- const gfx::Insets& insets);
// Deprecated: used the InsetsF version below.
static std::unique_ptr<Painter> CreateSolidFocusPainter(
SkColor color,
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_close.png b/chromium/ui/views/resources/default_100_percent/linux/linux_close.png
deleted file mode 100644
index df9a4161f94..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_close.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_close_hover.png b/chromium/ui/views/resources/default_100_percent/linux/linux_close_hover.png
deleted file mode 100644
index 4890b1ea872..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_close_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_close_pressed.png b/chromium/ui/views/resources/default_100_percent/linux/linux_close_pressed.png
deleted file mode 100644
index 5f0ccff27e2..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_close_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_maximize.png b/chromium/ui/views/resources/default_100_percent/linux/linux_maximize.png
deleted file mode 100644
index e1e8507d7eb..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_maximize.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_maximize_hover.png b/chromium/ui/views/resources/default_100_percent/linux/linux_maximize_hover.png
deleted file mode 100644
index fb60ae7d919..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_maximize_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_maximize_pressed.png b/chromium/ui/views/resources/default_100_percent/linux/linux_maximize_pressed.png
deleted file mode 100644
index a6534005610..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_maximize_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_minimize.png b/chromium/ui/views/resources/default_100_percent/linux/linux_minimize.png
deleted file mode 100644
index 1bccc31ccf6..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_minimize.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_minimize_hover.png b/chromium/ui/views/resources/default_100_percent/linux/linux_minimize_hover.png
deleted file mode 100644
index 805794e6c5b..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_minimize_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_minimize_pressed.png b/chromium/ui/views/resources/default_100_percent/linux/linux_minimize_pressed.png
deleted file mode 100644
index 2e914277c9c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_minimize_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_restore.png b/chromium/ui/views/resources/default_100_percent/linux/linux_restore.png
deleted file mode 100644
index 08d49372426..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_restore.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_restore_hover.png b/chromium/ui/views/resources/default_100_percent/linux/linux_restore_hover.png
deleted file mode 100644
index 8d10e989c84..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_restore_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/linux/linux_restore_pressed.png b/chromium/ui/views/resources/default_100_percent/linux/linux_restore_pressed.png
deleted file mode 100644
index 39b5b031de4..00000000000
--- a/chromium/ui/views/resources/default_100_percent/linux/linux_restore_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 c8a2a8aedf7..89517444317 100644
--- a/chromium/ui/views/resources/views_resources.grd
+++ b/chromium/ui/views/resources/views_resources.grd
@@ -36,16 +36,9 @@
<structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_PRESSED" file="common/checkbox_focused_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_CHECKBOX_HOVER" file="common/checkbox_hover.png" />
<structure type="chrome_scaled_image" name="IDR_CHECKBOX_PRESSED" file="common/checkbox_pressed.png" />
- <if expr="desktop_linux">
- <structure type="chrome_scaled_image" name="IDR_CLOSE" file="linux/linux_close.png" />
- <structure type="chrome_scaled_image" name="IDR_CLOSE_H" file="linux/linux_close_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_CLOSE_P" file="linux/linux_close_pressed.png" />
- </if>
- <if expr="not desktop_linux">
- <structure type="chrome_scaled_image" name="IDR_CLOSE" file="close.png" />
- <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_CLOSE" file="close.png" />
+ <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" />
<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" />
@@ -55,26 +48,12 @@
<structure type="chrome_scaled_image" name="IDR_FOLDER_OPEN_RTL" file="common/folder_open_rtl.png" />
<structure type="chrome_scaled_image" name="IDR_FRAME" file="frame_default.png" />
<structure type="chrome_scaled_image" name="IDR_FRAME_INACTIVE" file="frame_default_inactive.png" />
- <if expr="desktop_linux">
- <structure type="chrome_scaled_image" name="IDR_MAXIMIZE" file="linux/linux_maximize.png" />
- <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_H" file="linux/linux_maximize_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_P" file="linux/linux_maximize_pressed.png" />
- </if>
- <if expr="not desktop_linux">
- <structure type="chrome_scaled_image" name="IDR_MAXIMIZE" file="maximize.png" />
- <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_H" file="maximize_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_P" file="maximize_pressed.png" />
- </if>
- <if expr="desktop_linux">
- <structure type="chrome_scaled_image" name="IDR_MINIMIZE" file="linux/linux_minimize.png" />
- <structure type="chrome_scaled_image" name="IDR_MINIMIZE_H" file="linux/linux_minimize_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MINIMIZE_P" file="linux/linux_minimize_pressed.png" />
- </if>
- <if expr="not desktop_linux">
- <structure type="chrome_scaled_image" name="IDR_MINIMIZE" file="minimize.png" />
- <structure type="chrome_scaled_image" name="IDR_MINIMIZE_H" file="minimize_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_MINIMIZE_P" file="minimize_pressed.png" />
- </if>
+ <structure type="chrome_scaled_image" name="IDR_MAXIMIZE" file="maximize.png" />
+ <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_H" file="maximize_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_P" file="maximize_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_MINIMIZE" file="minimize.png" />
+ <structure type="chrome_scaled_image" name="IDR_MINIMIZE_H" file="minimize_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_MINIMIZE_P" file="minimize_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_RADIO" file="common/radio.png" />
<structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED" file="common/radio_checked.png" />
<structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED_DISABLED" file="common/radio_checked_inactive.png" />
@@ -89,16 +68,9 @@
<structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_PRESSED" file="common/radio_focused_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_RADIO_HOVER" file="common/radio_hover.png" />
<structure type="chrome_scaled_image" name="IDR_RADIO_PRESSED" file="common/radio_pressed.png" />
- <if expr="desktop_linux">
- <structure type="chrome_scaled_image" name="IDR_RESTORE" file="linux/linux_restore.png" />
- <structure type="chrome_scaled_image" name="IDR_RESTORE_H" file="linux/linux_restore_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_RESTORE_P" file="linux/linux_restore_pressed.png" />
- </if>
- <if expr="not desktop_linux ">
- <structure type="chrome_scaled_image" name="IDR_RESTORE" file="restore.png" />
- <structure type="chrome_scaled_image" name="IDR_RESTORE_H" file="restore_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_RESTORE_P" file="restore_pressed.png" />
- </if>
+ <structure type="chrome_scaled_image" name="IDR_RESTORE" file="restore.png" />
+ <structure type="chrome_scaled_image" name="IDR_RESTORE_H" file="restore_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_RESTORE_P" file="restore_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM" file="common/textbutton_hover_bottom.png" />
<structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM_LEFT" file="common/textbutton_hover_bottom_left.png" />
<structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM_RIGHT" file="common/textbutton_hover_bottom_right.png" />
diff --git a/chromium/ui/views/round_rect_painter.cc b/chromium/ui/views/round_rect_painter.cc
index 058cc97fe5f..a62adc90225 100644
--- a/chromium/ui/views/round_rect_painter.cc
+++ b/chromium/ui/views/round_rect_painter.cc
@@ -6,7 +6,6 @@
#include "cc/paint/paint_canvas.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/skia_util.h"
namespace views {
diff --git a/chromium/ui/views/selection_controller.cc b/chromium/ui/views/selection_controller.cc
index b04a99300b4..8dac911f6dd 100644
--- a/chromium/ui/views/selection_controller.cc
+++ b/chromium/ui/views/selection_controller.cc
@@ -39,6 +39,7 @@ bool SelectionController::OnMousePressed(
return true;
if (event.IsOnlyLeftMouseButton()) {
+ first_drag_location_ = event.location();
if (delegate_->SupportsDrag())
delegate_->SetTextBeingDragged(false);
@@ -206,7 +207,10 @@ void SelectionController::SelectThroughLastDragLocation() {
delegate_->OnBeforePointerAction();
- render_text->MoveCursorToPoint(last_drag_location_, true);
+ // Note that |first_drag_location_| is only used when
+ // RenderText::kDragToEndIfOutsideVerticalBounds, which is platform-specific.
+ render_text->MoveCursorToPoint(last_drag_location_, true,
+ first_drag_location_);
if (aggregated_clicks_ == 1) {
render_text->SelectWord();
diff --git a/chromium/ui/views/selection_controller.h b/chromium/ui/views/selection_controller.h
index c4382f1bf89..e8b15cdee05 100644
--- a/chromium/ui/views/selection_controller.h
+++ b/chromium/ui/views/selection_controller.h
@@ -85,9 +85,12 @@ class VIEWS_EXPORT SelectionController {
// Returns whether |point| is inside any substring of the text.
bool IsInsideText(const gfx::Point& point);
- // A timer and point used to modify the selection when dragging.
+ // A timer and point used to modify the selection when dragging. The
+ // |first_drag_location_| field is used to store where the drag-to-select
+ // started.
base::RepeatingTimer drag_selection_timer_;
gfx::Point last_drag_location_;
+ gfx::Point first_drag_location_;
// State variables used to track the last click time and location.
base::TimeTicks last_click_time_;
diff --git a/chromium/ui/views/selection_controller_unittest.cc b/chromium/ui/views/selection_controller_unittest.cc
index e28d5302029..626ff04eac1 100644
--- a/chromium/ui/views/selection_controller_unittest.cc
+++ b/chromium/ui/views/selection_controller_unittest.cc
@@ -101,6 +101,10 @@ class SelectionControllerTest : public ::testing::Test {
return render_text_->GetSubstringBounds(gfx::Range(index, index + 1))[0];
}
+ gfx::Point TranslatePointX(const gfx::Point& point, int delta) {
+ return point + gfx::Vector2d(delta, 0);
+ }
+
private:
void PressMouseButton(const gfx::Point& location, int button, bool focused) {
DCHECK(!(mouse_flags_ & button));
@@ -185,5 +189,31 @@ TEST_F(SelectionControllerTest, RightClickPastEndDoesntSelectLastWord) {
EXPECT_EQ("", GetSelectedText());
}
+// Regression test for https://crbug.com/731252
+// This test validates that drags which are:
+// a) Above or below the text, and
+// b) Past one end of the text
+// behave properly with regard to RenderText::kDragToEndIfOutsideVerticalBounds.
+// When that option is true, drags outside the text that are horizontally
+// "towards" the text should select all of it; when that option is false, those
+// drags should have no effect.
+TEST_F(SelectionControllerTest, DragPastEndUsesProperOrigin) {
+ SetText("abc def");
+
+ gfx::Point point = BoundsOfChar(6).top_right() + gfx::Vector2d(100, -10);
+
+ LeftMouseDown(point);
+ EXPECT_EQ("", GetSelectedText());
+
+ DragMouse(TranslatePointX(point, -1));
+ if (gfx::RenderText::kDragToEndIfOutsideVerticalBounds)
+ EXPECT_EQ("abc def", GetSelectedText());
+ else
+ EXPECT_EQ("", GetSelectedText());
+
+ DragMouse(TranslatePointX(point, 1));
+ EXPECT_EQ("", GetSelectedText());
+}
+
} // namespace
} // namespace views
diff --git a/chromium/ui/views/style/platform_style.cc b/chromium/ui/views/style/platform_style.cc
index da35f106869..65f03c0af17 100644
--- a/chromium/ui/views/style/platform_style.cc
+++ b/chromium/ui/views/style/platform_style.cc
@@ -56,6 +56,7 @@ const Button::NotifyAction PlatformStyle::kMenuNotifyActivationAction =
const Button::KeyClickAction PlatformStyle::kKeyClickActionOnSpace =
Button::CLICK_ON_KEY_RELEASE;
const bool PlatformStyle::kReturnClicksFocusedControl = true;
+const bool PlatformStyle::kTableViewSupportsKeyboardNavigationByCell = true;
const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = false;
const bool PlatformStyle::kUseRipples = true;
const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = false;
diff --git a/chromium/ui/views/style/platform_style.h b/chromium/ui/views/style/platform_style.h
index 36706db23ea..6eb55929f41 100644
--- a/chromium/ui/views/style/platform_style.h
+++ b/chromium/ui/views/style/platform_style.h
@@ -55,6 +55,11 @@ class VIEWS_EXPORT PlatformStyle {
// Otherwise, Return does nothing unless it is handled by an accelerator.
static const bool kReturnClicksFocusedControl;
+ // Whether cursor left and right can be used in a TableView to select and
+ // resize columns and whether a focus ring should be shown around the active
+ // cell.
+ static const bool kTableViewSupportsKeyboardNavigationByCell;
+
// Whether selecting a row in a TreeView selects the entire row or only the
// label for that row.
static const bool kTreeViewSelectionPaintsEntireRow;
diff --git a/chromium/ui/views/style/platform_style_mac.mm b/chromium/ui/views/style/platform_style_mac.mm
index be2299823a8..76fb02aca4e 100644
--- a/chromium/ui/views/style/platform_style_mac.mm
+++ b/chromium/ui/views/style/platform_style_mac.mm
@@ -5,7 +5,7 @@
#include "ui/views/style/platform_style.h"
#include "base/strings/sys_string_conversions.h"
-#include "ui/base/ui_features.h"
+#include "ui/base/buildflags.h"
#include "ui/gfx/color_utils.h"
#include "ui/views/controls/button/label_button.h"
#import "ui/views/controls/scrollbar/cocoa_scroll_bar.h"
@@ -39,6 +39,7 @@ const bool PlatformStyle::kSelectWordOnRightClick = true;
const bool PlatformStyle::kSelectAllOnRightClickWhenUnfocused = true;
const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = true;
const bool PlatformStyle::kTextfieldUsesDragCursorWhenDraggable = false;
+const bool PlatformStyle::kTableViewSupportsKeyboardNavigationByCell = false;
const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = true;
const bool PlatformStyle::kUseRipples = false;
const bool PlatformStyle::kPreferFocusRings = true;
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
index 93e0b4b85f3..f4d4a3dcc6f 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -19,7 +19,6 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
-#include "ui/gfx/path.h"
#include "ui/resources/grit/ui_resources.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
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 cd66a6ddc9d..5399b6ca2e1 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
@@ -75,10 +75,6 @@ class TouchSelectionControllerImplTest : public ViewsTestBase {
void SetUp() override {
ViewsTestBase::SetUp();
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
test_cursor_client_.reset(new aura::test::TestCursorClient(GetContext()));
}
@@ -321,10 +317,6 @@ class TouchSelectionControllerImplTest : public ViewsTestBase {
// Tests that the selection handles are placed appropriately when selection in
// a Textfield changes.
TEST_F(TouchSelectionControllerImplTest, SelectionInTextfieldTest) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateTextfield();
textfield_->SetText(ASCIIToUTF16("some text"));
// Tap the textfield to invoke touch selection.
@@ -358,10 +350,6 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInTextfieldTest) {
// Tests that the selection handles are placed appropriately in bidi text.
TEST_F(TouchSelectionControllerImplTest, SelectionInBidiTextfieldTest) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateTextfield();
textfield_->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2"));
// Tap the textfield to invoke touch selection.
@@ -414,10 +402,6 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInBidiTextfieldTest) {
// Tests if the SelectRect callback is called appropriately when selection
// handles are moved.
TEST_F(TouchSelectionControllerImplTest, SelectRectCallbackTest) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateTextfield();
textfield_->SetText(ASCIIToUTF16("textfield with selected text"));
// Tap the textfield to invoke touch selection.
@@ -460,10 +444,6 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectCallbackTest) {
}
TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateTextfield();
textfield_->SetText(WideToUTF16(L"abc\x05e1\x05e2\x05e3" L"def"));
// Tap the textfield to invoke touch selection.
@@ -592,10 +572,6 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
TEST_F(TouchSelectionControllerImplTest,
HiddenSelectionHandleRetainsCursorPosition) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
static const uint32_t selection_start = 10u;
SetupSelectionInvisibleHandle(selection_start);
// Drag the visible handle around and make sure the selection end point of the
@@ -614,10 +590,6 @@ TEST_F(TouchSelectionControllerImplTest,
// Tests that we can handle the hidden handle getting exposed as a result of a
// drag and that it maintains the correct orientation when exposed.
TEST_F(TouchSelectionControllerImplTest, HiddenSelectionHandleExposed) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
static const uint32_t selection_start = 0u;
SetupSelectionInvisibleHandle(selection_start);
@@ -635,10 +607,6 @@ TEST_F(TouchSelectionControllerImplTest, HiddenSelectionHandleExposed) {
TEST_F(TouchSelectionControllerImplTest,
DoubleTapInTextfieldWithCursorHandleShouldSelectText) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateTextfield();
textfield_->SetText(ASCIIToUTF16("some text"));
ui::test::EventGenerator generator(
@@ -738,10 +706,6 @@ class TestTouchEditable : public ui::TouchEditable {
// the cursor position relative to the client boundaries.
TEST_F(TouchSelectionControllerImplTest,
VisibilityOfHandleRegardingClientBounds) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateWidget();
TestTouchEditable touch_editable(widget_->GetNativeView());
@@ -789,10 +753,6 @@ TEST_F(TouchSelectionControllerImplTest,
}
TEST_F(TouchSelectionControllerImplTest, HandlesStackAboveParent) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
aura::Window* root = GetContext();
ui::EventTargeter* targeter =
root->GetHost()->dispatcher()->GetDefaultEventTargeter();
@@ -832,10 +792,6 @@ TEST_F(TouchSelectionControllerImplTest, HandlesStackAboveParent) {
}
TEST_F(TouchSelectionControllerImplTest, MouseEventDeactivatesTouchSelection) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateTextfield();
EXPECT_FALSE(GetSelectionController());
@@ -877,10 +833,6 @@ TEST_F(TouchSelectionControllerImplTest, MouseEventDeactivatesTouchSelection) {
}
TEST_F(TouchSelectionControllerImplTest, MouseCaptureChangedEventIgnored) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateTextfield();
EXPECT_FALSE(GetSelectionController());
@@ -900,10 +852,6 @@ TEST_F(TouchSelectionControllerImplTest, MouseCaptureChangedEventIgnored) {
}
TEST_F(TouchSelectionControllerImplTest, KeyEventDeactivatesTouchSelection) {
- // TODO: see comment in SetUp().
- if (IsMus())
- return;
-
CreateTextfield();
EXPECT_FALSE(GetSelectionController());
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 cf555e3f7af..6df1c3c2609 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
@@ -70,10 +70,6 @@ class TouchSelectionMenuRunnerViewsTest : public ViewsTestBase,
// Tests that the default touch selection menu runner is installed and opening
// and closing the menu works properly.
TEST_F(TouchSelectionMenuRunnerViewsTest, InstalledAndWorksProperly) {
- // See comment in SetUp().
- if (IsMus())
- return;
-
gfx::Rect menu_anchor(0, 0, 10, 10);
gfx::Size handle_size(10, 10);
@@ -101,10 +97,6 @@ TEST_F(TouchSelectionMenuRunnerViewsTest, InstalledAndWorksProperly) {
// Tests that anchor rect for the quick menu is adjusted correctly based on the
// distance of handles.
TEST_F(TouchSelectionMenuRunnerViewsTest, QuickMenuAdjustsAnchorRect) {
- // See comment in SetUp().
- if (IsMus())
- return;
-
gfx::Size handle_size(10, 10);
TouchSelectionMenuRunnerViews::TestApi test_api(
static_cast<TouchSelectionMenuRunnerViews*>(
@@ -137,10 +129,6 @@ TEST_F(TouchSelectionMenuRunnerViewsTest, QuickMenuAdjustsAnchorRect) {
// Tests that running one of menu actions closes the menu properly.
TEST_F(TouchSelectionMenuRunnerViewsTest, RunningActionClosesProperly) {
- // See comment in SetUp().
- if (IsMus())
- return;
-
gfx::Rect menu_anchor(0, 0, 10, 10);
gfx::Size handle_size(10, 10);
TouchSelectionMenuRunnerViews::TestApi test_api(
@@ -172,10 +160,6 @@ TEST_F(TouchSelectionMenuRunnerViewsTest, RunningActionClosesProperly) {
// Tests that closing the menu widget cleans up the menu runner state properly.
TEST_F(TouchSelectionMenuRunnerViewsTest, ClosingWidgetClosesProperly) {
- // See comment in SetUp().
- if (IsMus())
- return;
-
gfx::Rect menu_anchor(0, 0, 10, 10);
gfx::Size handle_size(10, 10);
TouchSelectionMenuRunnerViews::TestApi test_api(
diff --git a/chromium/ui/views/mus/unittests_manifest.json b/chromium/ui/views/unittests_manifest.json
index ad202025314..172d89827bc 100644
--- a/chromium/ui/views/mus/unittests_manifest.json
+++ b/chromium/ui/views/unittests_manifest.json
@@ -1,6 +1,6 @@
{
- "name": "views_mus_unittests",
- "display_name": "Views Mus Unittests",
+ "name": "views_unittests",
+ "display_name": "Views Unittests",
"interface_provider_specs": {
"service_manager:connector": {
"requires": {
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index b2429b98c42..36a82eb57cf 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -39,7 +39,6 @@
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/interpolated_transform.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h"
@@ -155,85 +154,6 @@ Widget* View::GetWidget() {
return const_cast<Widget*>(const_cast<const View*>(this)->GetWidget());
}
-void View::AddChildView(View* view) {
- if (view->parent_ == this)
- return;
- AddChildViewAt(view, child_count());
-}
-
-void View::AddChildViewAt(View* view, int index) {
- CHECK_NE(view, this) << "You cannot add a view as its own child";
- DCHECK_GE(index, 0);
- DCHECK_LE(index, child_count());
-
- // If |view| has a parent, remove it from its parent.
- View* parent = view->parent_;
- ui::NativeTheme* old_theme = nullptr;
- Widget* old_widget = nullptr;
- if (parent) {
- old_theme = view->GetNativeTheme();
- old_widget = view->GetWidget();
- if (parent == this) {
- ReorderChildView(view, index);
- return;
- }
- parent->DoRemoveChildView(view, true, true, false, this);
- }
-
- // Sets the prev/next focus views.
- InitFocusSiblings(view, index);
-
- view->parent_ = this;
-#if DCHECK_IS_ON()
- DCHECK(!iterating_);
-#endif
- children_.insert(children_.begin() + index, view);
-
- // Ensure the layer tree matches the view tree before calling to any client
- // code. This way if client code further modifies the view tree we are in a
- // sane state.
- const bool did_reparent_any_layers = view->UpdateParentLayers();
- Widget* widget = GetWidget();
- if (did_reparent_any_layers && widget)
- widget->LayerTreeChanged();
-
- ReorderLayers();
-
- // Make sure the visibility of the child layers are correct.
- // If any of the parent View is hidden, then the layers of the subtree
- // rooted at |this| should be hidden. Otherwise, all the child layers should
- // inherit the visibility of the owner View.
- view->UpdateLayerVisibility();
-
- if (widget) {
- const ui::NativeTheme* new_theme = view->GetNativeTheme();
- if (new_theme != old_theme)
- view->PropagateNativeThemeChanged(new_theme);
- }
-
- ViewHierarchyChangedDetails details(true, this, view, parent);
-
- for (View* v = this; v; v = v->parent_)
- v->ViewHierarchyChangedImpl(false, details);
-
- view->PropagateAddNotifications(details, widget && widget != old_widget);
-
- UpdateTooltip();
-
- if (widget) {
- RegisterChildrenForVisibleBoundsNotification(view);
-
- if (view->visible())
- view->SchedulePaint();
- }
-
- if (layout_manager_.get())
- layout_manager_->ViewAdded(this, view);
-
- for (ViewObserver& observer : observers_)
- observer.OnChildViewAdded(this, view);
-}
-
void View::ReorderChildView(View* view, int index) {
DCHECK_EQ(view->parent_, this);
if (index < 0)
@@ -266,6 +186,7 @@ void View::ReorderChildView(View* view, int index) {
observer.OnChildViewReordered(this, view);
ReorderLayers();
+ InvalidateLayout();
}
void View::RemoveChildView(View* view) {
@@ -342,8 +263,7 @@ void View::SetY(int y) {
gfx::Rect View::GetContentsBounds() const {
gfx::Rect contents_bounds(GetLocalBounds());
- if (border_.get())
- contents_bounds.Inset(border_->GetInsets());
+ contents_bounds.Inset(GetInsets());
return contents_bounds;
}
@@ -440,6 +360,12 @@ int View::GetHeightForWidth(int w) const {
}
void View::SetVisible(bool visible) {
+ if (parent_) {
+ LayoutManager* const layout_manager = parent_->GetLayoutManager();
+ if (layout_manager && layout_manager->view_setting_visibility_on_ != this)
+ layout_manager->ViewVisibilitySet(parent_, this, visible);
+ }
+
if (visible != visible_) {
// If the View is currently visible, schedule paint to refresh parent.
// TODO(beng): not sure we should be doing this if we have a layer.
@@ -874,7 +800,7 @@ void View::Paint(const PaintInfo& parent_paint_info) {
clip_recorder.ClipRect(gfx::Rect(paint_info.paint_recording_size()) +
paint_info.offset_from_parent());
} else {
- gfx::Path clip_path_in_parent = clip_path_;
+ SkPath clip_path_in_parent = clip_path_;
// Transform |clip_path_| from local space to parent recording space.
gfx::Transform to_parent_recording_space;
@@ -1360,7 +1286,7 @@ gfx::Point View::GetKeyboardContextMenuLocation() {
// Drag and drop ---------------------------------------------------------------
bool View::GetDropFormats(int* formats,
- std::set<ui::Clipboard::FormatType>* format_types) {
+ std::set<ui::ClipboardFormatType>* format_types) {
return false;
}
@@ -1974,6 +1900,79 @@ void View::PaintDebugRects(const PaintInfo& parent_paint_info) {
// Tree operations -------------------------------------------------------------
+void View::AddChildViewAtImpl(View* view, int index) {
+ CHECK_NE(view, this) << "You cannot add a view as its own child";
+ DCHECK_GE(index, 0);
+ DCHECK_LE(index, child_count());
+
+ // If |view| has a parent, remove it from its parent.
+ View* parent = view->parent_;
+ ui::NativeTheme* old_theme = nullptr;
+ Widget* old_widget = nullptr;
+ if (parent) {
+ old_theme = view->GetNativeTheme();
+ old_widget = view->GetWidget();
+ if (parent == this) {
+ ReorderChildView(view, index);
+ return;
+ }
+ parent->DoRemoveChildView(view, true, true, false, this);
+ }
+
+ // Sets the prev/next focus views.
+ InitFocusSiblings(view, index);
+
+ view->parent_ = this;
+#if DCHECK_IS_ON()
+ DCHECK(!iterating_);
+#endif
+ children_.insert(children_.begin() + index, view);
+
+ // Ensure the layer tree matches the view tree before calling to any client
+ // code. This way if client code further modifies the view tree we are in a
+ // sane state.
+ const bool did_reparent_any_layers = view->UpdateParentLayers();
+ Widget* widget = GetWidget();
+ if (did_reparent_any_layers && widget)
+ widget->LayerTreeChanged();
+
+ ReorderLayers();
+
+ // Make sure the visibility of the child layers are correct.
+ // If any of the parent View is hidden, then the layers of the subtree
+ // rooted at |this| should be hidden. Otherwise, all the child layers should
+ // inherit the visibility of the owner View.
+ view->UpdateLayerVisibility();
+
+ if (widget) {
+ const ui::NativeTheme* new_theme = view->GetNativeTheme();
+ if (new_theme != old_theme)
+ view->PropagateNativeThemeChanged(new_theme);
+ }
+
+ ViewHierarchyChangedDetails details(true, this, view, parent);
+
+ for (View* v = this; v; v = v->parent_)
+ v->ViewHierarchyChangedImpl(false, details);
+
+ view->PropagateAddNotifications(details, widget && widget != old_widget);
+
+ UpdateTooltip();
+
+ if (widget) {
+ RegisterChildrenForVisibleBoundsNotification(view);
+
+ if (view->visible())
+ view->SchedulePaint();
+ }
+
+ if (layout_manager_.get())
+ layout_manager_->ViewAdded(this, view);
+
+ for (ViewObserver& observer : observers_)
+ observer.OnChildViewAdded(this, view);
+}
+
void View::DoRemoveChildView(View* view,
bool update_focus_cycle,
bool update_tool_tip,
diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h
index 998c87a3d6f..2aa7df41f17 100644
--- a/chromium/ui/views/view.h
+++ b/chromium/ui/views/view.h
@@ -20,9 +20,11 @@
#include "base/logging.h"
#include "base/macros.h"
#include "build/build_config.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/class_property.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data.h"
@@ -37,7 +39,6 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/path.h"
#include "ui/views/paint_info.h"
#include "ui/views/view_targeter.h"
#include "ui/views/views_export.h"
@@ -51,7 +52,6 @@ using ui::OSExchangeData;
namespace gfx {
class Canvas;
class Insets;
-class Path;
class Transform;
} // namespace gfx
@@ -273,8 +273,37 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
virtual Widget* GetWidget();
// Adds |view| as a child of this view, optionally at |index|.
- void AddChildView(View* view);
- void AddChildViewAt(View* view, int index);
+ // Returns the raw pointer for callers which want to hold a pointer to the
+ // added view. This requires declaring the function as a template in order to
+ // return the actual passed-in type.
+ template <typename T>
+ T* AddChildView(std::unique_ptr<T> view) {
+ DCHECK(!view->owned_by_client())
+ << "This should only be called if the client is passing ownership of "
+ "|view| to the parent View.";
+ return AddChildView<T>(view.release());
+ }
+ template <typename T>
+ T* AddChildViewAt(std::unique_ptr<T> view, int index) {
+ DCHECK(!view->owned_by_client())
+ << "This should only be called if the client is passing ownership of "
+ "|view| to the parent View.";
+ return AddChildViewAt<T>(view.release(), index);
+ }
+
+ // Prefer using the AddChildView(std::unique_ptr) overloads over raw pointers
+ // for new code.
+ template <typename T>
+ T* AddChildView(T* view) {
+ if (static_cast<View*>(view)->parent_ != this)
+ AddChildViewAtImpl(view, child_count());
+ return view;
+ }
+ template <typename T>
+ T* AddChildViewAt(T* view, int index) {
+ AddChildViewAtImpl(view, index);
+ return view;
+ }
// Moves |view| to the specified |index|. A negative value for |index| moves
// the view at the end.
@@ -434,7 +463,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
gfx::Transform GetTransform() const;
// Clipping is done relative to the view's local bounds.
- void set_clip_path(const gfx::Path& path) { clip_path_ = path; }
+ void set_clip_path(const SkPath& path) { clip_path_ = path; }
// Sets the transform to the supplied transform.
void SetTransform(const gfx::Transform& transform);
@@ -514,7 +543,6 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// specific to the current Layout Manager)
virtual void Layout();
- // TODO(beng): I think we should remove this.
// Mark this view and all parents to require a relayout. This ensures the
// next call to Layout() will propagate to this view, even if the bounds of
// parent views do not change.
@@ -1064,9 +1092,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// |formats| is a bitmask of the formats defined bye OSExchangeData::Format.
// The default implementation returns false, which means the view doesn't
// support dropping.
- virtual bool GetDropFormats(
- int* formats,
- std::set<ui::Clipboard::FormatType>* format_types);
+ virtual bool GetDropFormats(int* formats,
+ std::set<ui::ClipboardFormatType>* format_types);
// Override and return true if the data must be available before any drop
// methods should be invoked. The default is false.
@@ -1461,6 +1488,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Tree operations -----------------------------------------------------------
+ // Adds |view| as a child of this view at |index|.
+ void AddChildViewAtImpl(View* view, int index);
+
// Removes |view| from the hierarchy tree. If |update_focus_cycle| is true,
// the next and previous focusable views of views pointing to this view are
// updated. If |update_tool_tip| is true, the tooltip is updated. If
@@ -1748,7 +1778,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Painting will be clipped to this path. TODO(estade): this doesn't work for
// layers.
- gfx::Path clip_path_;
+ SkPath clip_path_;
// Layout --------------------------------------------------------------------
diff --git a/chromium/ui/views/view_properties.cc b/chromium/ui/views/view_properties.cc
index 1b19cb4f490..619579fc487 100644
--- a/chromium/ui/views/view_properties.cc
+++ b/chromium/ui/views/view_properties.cc
@@ -26,6 +26,7 @@ namespace views {
DEFINE_UI_CLASS_PROPERTY_KEY(int, kHitTestComponentKey, HTNOWHERE);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Insets, kMarginsKey, nullptr);
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Insets, kInternalPaddingKey, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(views::BubbleDialogDelegateView*,
kAnchoredDialogKey,
nullptr);
diff --git a/chromium/ui/views/view_properties.h b/chromium/ui/views/view_properties.h
index a706ce8d713..abb17897844 100644
--- a/chromium/ui/views/view_properties.h
+++ b/chromium/ui/views/view_properties.h
@@ -25,8 +25,20 @@ VIEWS_EXPORT extern const ui::ClassProperty<int>* const kHitTestComponentKey;
// A property to store margins around the outer perimeter of the view. Margins
// are outside the bounds of the view. This is used by various layout managers
// to position views with the proper spacing between them.
+//
+// Used by multiple layout managers.
VIEWS_EXPORT extern const ui::ClassProperty<gfx::Insets*>* const kMarginsKey;
+// A property to store the internal padding contained in a view. When doing
+// layout, this padding is counted against the required margin around the view,
+// effectively reducing the size of the margin (to a minimum of zero). Examples
+// include expansion of buttons in touch mode and empty areas that serve as
+// resize handles.
+//
+// Used by FlexLayout.
+VIEWS_EXPORT extern const ui::ClassProperty<gfx::Insets*>* const
+ kInternalPaddingKey;
+
// A property to store the bubble dialog anchored to this view, to
// enable the bubble's contents to be included in the focus order.
VIEWS_EXPORT extern const ui::ClassProperty<BubbleDialogDelegateView*>* const
diff --git a/chromium/ui/views/view_targeter_unittest.cc b/chromium/ui/views/view_targeter_unittest.cc
index 9998b3b0d24..00345a34586 100644
--- a/chromium/ui/views/view_targeter_unittest.cc
+++ b/chromium/ui/views/view_targeter_unittest.cc
@@ -6,10 +6,10 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/events/event_targeter.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/gfx/path.h"
#include "ui/views/masked_targeter_delegate.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view_targeter.h"
@@ -61,7 +61,7 @@ class TestMaskedView : public View, public MaskedTargeterDelegate {
private:
// MaskedTargeterDelegate:
- bool GetHitTestMask(gfx::Path* mask) const override {
+ bool GetHitTestMask(SkPath* mask) const override {
DCHECK(mask);
SkScalar w = SkIntToScalar(width());
SkScalar h = SkIntToScalar(height());
diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc
index e34bf29ac18..0f09d44f3c6 100644
--- a/chromium/ui/views/view_unittest.cc
+++ b/chromium/ui/views/view_unittest.cc
@@ -23,6 +23,7 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/paint/display_item_list.h"
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/l10n/l10n_util.h"
@@ -38,9 +39,9 @@
#include "ui/events/scoped_target_handler.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/transform.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/native_theme/test_native_theme.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/background.h"
#include "ui/views/controls/native/native_view_host.h"
@@ -3572,15 +3573,11 @@ TEST_F(ViewTest, GetIndexOf) {
TEST_F(ViewTest, ReorderChildren) {
View root;
- View* child = new View();
- root.AddChildView(child);
+ View* child = root.AddChildView(std::make_unique<View>());
- View* foo1 = new View();
- child->AddChildView(foo1);
- View* foo2 = new View();
- child->AddChildView(foo2);
- View* foo3 = new View();
- child->AddChildView(foo3);
+ View* foo1 = child->AddChildView(std::make_unique<View>());
+ View* foo2 = child->AddChildView(std::make_unique<View>());
+ View* foo3 = child->AddChildView(std::make_unique<View>());
foo1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
foo2->SetFocusBehavior(View::FocusBehavior::ALWAYS);
foo3->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -3727,13 +3724,11 @@ TEST_F(ViewTest, AdvanceFocusIfNecessaryForUnfocusableView) {
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(params);
- View* view1 = new View();
+ View* view1 = widget.GetRootView()->AddChildView(std::make_unique<View>());
view1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- widget.GetRootView()->AddChildView(view1);
- View* view2 = new View();
+ View* view2 = widget.GetRootView()->AddChildView(std::make_unique<View>());
view2->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- widget.GetRootView()->AddChildView(view2);
FocusManager* focus_manager = widget.GetFocusManager();
ASSERT_TRUE(focus_manager);
@@ -3904,16 +3899,13 @@ TEST_F(ViewLayerTest, NestedLayerToggling) {
widget()->SetContentsView(content_view);
// Create v1, give it a bounds and verify everything is set up correctly.
- View* v1 = new View;
- content_view->AddChildView(v1);
+ View* v1 = content_view->AddChildView(std::make_unique<View>());
v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
- View* v2 = new View;
- v1->AddChildView(v2);
+ View* v2 = v1->AddChildView(std::make_unique<View>());
- View* v3 = new View;
+ View* v3 = v2->AddChildView(std::make_unique<View>());
v3->SetPaintToLayer();
- v2->AddChildView(v3);
ASSERT_TRUE(v3->layer() != NULL);
// At this point we have v1-v2-v3. v3 has a layer, v1 and v2 don't.
@@ -3926,8 +3918,7 @@ TEST_F(ViewLayerTest, LayerAnimator) {
View* content_view = new View;
widget()->SetContentsView(content_view);
- View* v1 = new View;
- content_view->AddChildView(v1);
+ View* v1 = content_view->AddChildView(std::make_unique<View>());
v1->SetPaintToLayer();
EXPECT_TRUE(v1->layer() != NULL);
@@ -3947,13 +3938,11 @@ TEST_F(ViewLayerTest, BoundsChangeWithLayer) {
View* content_view = new View;
widget()->SetContentsView(content_view);
- View* v1 = new View;
- content_view->AddChildView(v1);
+ View* v1 = content_view->AddChildView(std::make_unique<View>());
v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
- View* v2 = new View;
+ View* v2 = v1->AddChildView(std::make_unique<View>());
v2->SetBoundsRect(gfx::Rect(10, 11, 40, 50));
- v1->AddChildView(v2);
v2->SetPaintToLayer();
ASSERT_TRUE(v2->layer() != NULL);
EXPECT_EQ(gfx::Rect(30, 41, 40, 50), v2->layer()->bounds());
@@ -4037,10 +4026,9 @@ TEST_F(ViewLayerTest, ResizeParentInRTL) {
int content_width = view->width();
// Create a paints-to-layer view |v1|.
- View* v1 = new View;
+ View* v1 = view->AddChildView(std::make_unique<View>());
v1->SetPaintToLayer();
v1->SetBounds(10, 10, 20, 10);
- view->AddChildView(v1);
EXPECT_EQ(gfx::Rect(content_width - 30, 10, 20, 10),
v1->layer()->bounds());
@@ -4238,9 +4226,8 @@ TEST_F(ViewLayerTest, ScheduledRectsInParentAfterSchedulingPaint) {
TestView parent_view;
parent_view.SetBounds(10, 10, 100, 100);
- TestView* child_view = new TestView;
+ TestView* child_view = parent_view.AddChildView(std::make_unique<TestView>());
child_view->SetBounds(5, 6, 10, 20);
- parent_view.AddChildView(child_view);
parent_view.scheduled_paint_rects_.clear();
SchedulePaintOnParent(child_view);
@@ -4253,8 +4240,7 @@ TEST_F(ViewLayerTest, ParentPaintWhenSwitchingPaintToLayerFromFalseToTrue) {
TestView parent_view;
parent_view.SetBounds(10, 11, 12, 13);
- TestView* child_view = new TestView;
- parent_view.AddChildView(child_view);
+ TestView* child_view = parent_view.AddChildView(std::make_unique<TestView>());
parent_view.scheduled_paint_rects_.clear();
child_view->SetPaintToLayer();
@@ -4265,9 +4251,8 @@ TEST_F(ViewLayerTest, NoParentPaintWhenSwitchingPaintToLayerFromTrueToTrue) {
TestView parent_view;
parent_view.SetBounds(10, 11, 12, 13);
- TestView* child_view = new TestView;
+ TestView* child_view = parent_view.AddChildView(std::make_unique<TestView>());
child_view->SetPaintToLayer();
- parent_view.AddChildView(child_view);
parent_view.scheduled_paint_rects_.clear();
EXPECT_EQ(0U, parent_view.scheduled_paint_rects_.size());
@@ -4280,16 +4265,13 @@ TEST_F(ViewLayerTest, VisibilityChildLayers) {
v1->SetPaintToLayer();
widget()->SetContentsView(v1);
- View* v2 = new View;
- v1->AddChildView(v2);
+ View* v2 = v1->AddChildView(std::make_unique<View>());
- View* v3 = new View;
- v2->AddChildView(v3);
+ View* v3 = v2->AddChildView(std::make_unique<View>());
v3->SetVisible(false);
- View* v4 = new View;
+ View* v4 = v3->AddChildView(std::make_unique<View>());
v4->SetPaintToLayer();
- v3->AddChildView(v4);
EXPECT_TRUE(v1->layer()->IsDrawn());
EXPECT_FALSE(v4->layer()->IsDrawn());
@@ -4346,12 +4328,10 @@ TEST_F(ViewLayerTest, DISABLED_ViewLayerTreesInSync) {
TEST_F(ViewLayerTest, ReorderUnderWidget) {
View* content = new View;
widget()->SetContentsView(content);
- View* c1 = new View;
+ View* c1 = content->AddChildView(std::make_unique<View>());
c1->SetPaintToLayer();
- content->AddChildView(c1);
- View* c2 = new View;
+ View* c2 = content->AddChildView(std::make_unique<View>());
c2->SetPaintToLayer();
- content->AddChildView(c2);
ui::Layer* parent_layer = c1->layer()->parent();
ASSERT_TRUE(parent_layer);
@@ -4389,12 +4369,10 @@ TEST_F(ViewLayerTest, RecreateLayerZOrder) {
std::unique_ptr<View> v(new View());
v->SetPaintToLayer();
- View* v1 = new View();
+ View* v1 = v->AddChildView(std::make_unique<View>());
v1->SetPaintToLayer();
- v->AddChildView(v1);
- View* v2 = new View();
+ View* v2 = v->AddChildView(std::make_unique<View>());
v2->SetPaintToLayer();
- v->AddChildView(v2);
// Test the initial z-order.
const std::vector<ui::Layer*>& child_layers_pre = v->layer()->children();
@@ -4419,12 +4397,10 @@ TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) {
View* v = new View();
widget()->SetContentsView(v);
- View* v1 = new View();
+ View* v1 = v->AddChildView(std::make_unique<View>());
v1->SetPaintToLayer();
- v->AddChildView(v1);
- View* v2 = new View();
+ View* v2 = v->AddChildView(std::make_unique<View>());
v2->SetPaintToLayer();
- v->AddChildView(v2);
ui::Layer* root_layer = GetRootLayer();
@@ -4485,16 +4461,17 @@ std::string ToString(const gfx::Vector2dF& vector) {
} // namespace
TEST_F(ViewLayerTest, SnapLayerToPixel) {
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
View* v1 = new View;
- View* v11 = new View;
- v1->AddChildView(v11);
+ View* v11 = v1->AddChildView(std::make_unique<View>());
widget()->SetContentsView(v1);
const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
GetRootLayer()->GetCompositor()->SetScaleAndSize(
- 1.25f, size, viz::LocalSurfaceIdAllocation());
+ 1.25f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
v11->SetBoundsRect(gfx::Rect(1, 1, 10, 10));
v1->SetBoundsRect(gfx::Rect(1, 1, 10, 10));
@@ -4509,7 +4486,7 @@ TEST_F(ViewLayerTest, SnapLayerToPixel) {
// DSF change should get propagated and update offsets.
GetRootLayer()->GetCompositor()->SetScaleAndSize(
- 1.5f, size, viz::LocalSurfaceIdAllocation());
+ 1.5f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
EXPECT_EQ("0.33 0.33", ToString(v1->layer()->subpixel_position_offset()));
EXPECT_EQ("0.33 0.33", ToString(v11->layer()->subpixel_position_offset()));
@@ -4523,7 +4500,7 @@ TEST_F(ViewLayerTest, SnapLayerToPixel) {
// Setting integral DSF should reset the offset.
GetRootLayer()->GetCompositor()->SetScaleAndSize(
- 2.0f, size, viz::LocalSurfaceIdAllocation());
+ 2.0f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
EXPECT_EQ("0.00 0.00", ToString(v11->layer()->subpixel_position_offset()));
}
@@ -4583,17 +4560,17 @@ class ViewLayerPixelCanvasTest : public ViewLayerTest {
};
TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
View* v1 = new View;
- View* v2 = new View;
- PaintLayerView* v3 = new PaintLayerView;
- v1->AddChildView(v2);
- v2->AddChildView(v3);
+ View* v2 = v1->AddChildView(std::make_unique<View>());
+ PaintLayerView* v3 = v2->AddChildView(std::make_unique<PaintLayerView>());
widget()->SetContentsView(v1);
const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
GetRootLayer()->GetCompositor()->SetScaleAndSize(
- 1.6f, size, viz::LocalSurfaceIdAllocation());
+ 1.6f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
v3->SetBoundsRect(gfx::Rect(14, 13, 13, 5));
v2->SetBoundsRect(gfx::Rect(7, 7, 50, 50));
@@ -4609,7 +4586,7 @@ TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
// DSF change should get propagated and update offsets.
GetRootLayer()->GetCompositor()->SetScaleAndSize(
- 1.5f, size, viz::LocalSurfaceIdAllocation());
+ 1.5f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
EXPECT_EQ("0.33 0.33", ToString(v1->layer()->subpixel_position_offset()));
EXPECT_EQ("0.33 0.67", ToString(v3->layer()->subpixel_position_offset()));
@@ -4619,7 +4596,7 @@ TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
v1->SetPaintToLayer();
GetRootLayer()->GetCompositor()->SetScaleAndSize(
- 1.33f, size, viz::LocalSurfaceIdAllocation());
+ 1.33f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
EXPECT_EQ("0.02 0.02", ToString(v1->layer()->subpixel_position_offset()));
EXPECT_EQ("0.05 -0.45", ToString(v3->layer()->subpixel_position_offset()));
@@ -4636,7 +4613,7 @@ TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
// Setting integral DSF should reset the offset.
GetRootLayer()->GetCompositor()->SetScaleAndSize(
- 2.0f, size, viz::LocalSurfaceIdAllocation());
+ 2.0f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
EXPECT_EQ("0.00 0.00", ToString(v3->layer()->subpixel_position_offset()));
}
@@ -4669,12 +4646,12 @@ void TestView::OnNativeThemeChanged(const ui::NativeTheme* native_theme) {
TEST_F(ViewTest, OnNativeThemeChanged) {
TestView* test_view = new TestView();
EXPECT_FALSE(test_view->native_theme_);
- TestView* test_view_child = new TestView();
- EXPECT_FALSE(test_view_child->native_theme_);
// Child view added before the widget hierarchy exists should get the
// new native theme notification.
- test_view->AddChildView(test_view_child);
+ TestView* test_view_child =
+ test_view->AddChildView(std::make_unique<TestView>());
+ EXPECT_FALSE(test_view_child->native_theme_);
std::unique_ptr<Widget> widget(new Widget);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
@@ -4689,8 +4666,8 @@ TEST_F(ViewTest, OnNativeThemeChanged) {
// Child view added after the widget hierarchy exists should also get the
// notification.
- TestView* test_view_child_2 = new TestView();
- test_view->AddChildView(test_view_child_2);
+ TestView* test_view_child_2 =
+ test_view->AddChildView(std::make_unique<TestView>());
EXPECT_TRUE(test_view_child_2->native_theme_);
EXPECT_EQ(widget->GetNativeTheme(), test_view_child_2->native_theme_);
@@ -4713,16 +4690,14 @@ class TestEventHandler : public ui::EventHandler {
};
TEST_F(ViewTest, ScopedTargetHandlerReceivesEvents) {
- TestView* v = new TestView();
- v->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
-
std::unique_ptr<Widget> widget(new Widget);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(50, 50, 350, 350);
widget->Init(params);
View* root = widget->GetRootView();
- root->AddChildView(v);
+ TestView* v = root->AddChildView(std::make_unique<TestView>());
+ v->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
v->Reset();
{
TestEventHandler handler(v);
@@ -4778,7 +4753,7 @@ class ViewThatAddsViewInOnNativeThemeChanged : public View {
// View:
void OnNativeThemeChanged(const ui::NativeTheme* theme) override {
on_native_theme_changed_called_ = true;
- GetWidget()->GetRootView()->AddChildView(new View);
+ GetWidget()->GetRootView()->AddChildView(std::make_unique<View>());
}
private:
@@ -4787,46 +4762,10 @@ class ViewThatAddsViewInOnNativeThemeChanged : public View {
DISALLOW_COPY_AND_ASSIGN(ViewThatAddsViewInOnNativeThemeChanged);
};
-// See comment above test for details.
-class TestNativeTheme : public ui::NativeTheme {
- public:
- TestNativeTheme() {}
- ~TestNativeTheme() override {}
-
- // ui::NativeTheme:
- SkColor GetSystemColor(ColorId color_id) const override {
- return SK_ColorRED;
- }
- gfx::Size GetPartSize(Part part,
- State state,
- const ExtraParams& extra) const override {
- return gfx::Size();
- }
- void Paint(cc::PaintCanvas* canvas,
- Part part,
- State state,
- const gfx::Rect& rect,
- const ExtraParams& extra) const override {}
-
- bool SupportsNinePatch(Part part) const override { return false; }
- gfx::Size GetNinePatchCanvasSize(Part part) const override {
- return gfx::Size();
- }
- gfx::Rect GetNinePatchAperture(Part part) const override {
- return gfx::Rect();
- }
- bool UsesHighContrastColors() const override { return false; }
- bool SystemDarkModeEnabled() const override { return false; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestNativeTheme);
-};
-
// Creates and adds a new child view to |parent| that has a layer.
void AddViewWithChildLayer(View* parent) {
- View* child = new View;
+ View* child = parent->AddChildView(std::make_unique<View>());
child->SetPaintToLayer();
- parent->AddChildView(child);
}
// This test does the following:
@@ -4838,7 +4777,7 @@ void AddViewWithChildLayer(View* parent) {
// before the layer hierarchy was updated. OnNativeThemeChanged() should be
// called after the layer hierarchy matches the view hierarchy.
TEST_F(ViewTest, CrashOnAddFromFromOnNativeThemeChanged) {
- TestNativeTheme theme;
+ ui::TestNativeTheme theme;
WidgetWithCustomTheme widget(&theme);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
@@ -4847,8 +4786,8 @@ TEST_F(ViewTest, CrashOnAddFromFromOnNativeThemeChanged) {
AddViewWithChildLayer(widget.GetRootView());
ViewThatAddsViewInOnNativeThemeChanged* v =
- new ViewThatAddsViewInOnNativeThemeChanged;
- widget.GetRootView()->AddChildView(v);
+ widget.GetRootView()->AddChildView(
+ std::make_unique<ViewThatAddsViewInOnNativeThemeChanged>());
EXPECT_TRUE(v->on_native_theme_changed_called());
}
@@ -4971,18 +4910,15 @@ TEST_F(ViewTest, AttachChildViewWithComplicatedLayers) {
parent_view->SetPaintToLayer();
// child_view1 has layer and has id OrderableView::VIEW_ID_RAISED.
- View* child_view1 = new View;
+ View* child_view1 = parent_view->AddChildView(std::make_unique<View>());
child_view1->SetPaintToLayer();
child_view1->set_id(OrderableView::VIEW_ID_RAISED);
- parent_view->AddChildView(child_view1);
// child_view2 has no layer.
- View* child_view2 = new View;
+ View* child_view2 = parent_view->AddChildView(std::make_unique<View>());
// grand_child_view has layer.
- View* grand_child_view = new View();
+ View* grand_child_view = child_view2->AddChildView(std::make_unique<View>());
grand_child_view->SetPaintToLayer();
- child_view2->AddChildView(grand_child_view);
- parent_view->AddChildView(child_view2);
const std::vector<ui::Layer*>& layers = parent_view->layer()->children();
EXPECT_EQ(2u, layers.size());
EXPECT_EQ(layers[0], grand_child_view->layer());
@@ -5158,12 +5094,10 @@ TEST_F(ViewObserverTest, ViewBoundsChanged) {
TEST_F(ViewObserverTest, ChildViewReordered) {
std::unique_ptr<View> view = NewView();
- std::unique_ptr<View> child_view = NewView();
- std::unique_ptr<View> child_view2 = NewView();
- view->AddChildView(child_view.get());
- view->AddChildView(child_view2.get());
- view->ReorderChildView(child_view2.get(), 0);
- EXPECT_EQ(child_view2.get(), view_reordered());
+ view->AddChildView(NewView());
+ View* child_view2 = view->AddChildView(NewView());
+ view->ReorderChildView(child_view2, 0);
+ EXPECT_EQ(child_view2, view_reordered());
}
// Provides a simple parent view implementation which tracks layer change
diff --git a/chromium/ui/views/view_unittest_aura.cc b/chromium/ui/views/view_unittest_aura.cc
index 231afc33087..edbd6454a2a 100644
--- a/chromium/ui/views/view_unittest_aura.cc
+++ b/chromium/ui/views/view_unittest_aura.cc
@@ -72,11 +72,6 @@ class ViewAuraTest : public ViewsTestBase {
// +-- v8
// +-- v9
TEST_F(ViewAuraTest, RecreateLayersWithWindows) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
Widget* w1 = CreateControlWidget(GetContext(), gfx::Rect(0, 0, 100, 100));
w1->GetNativeView()->layer()->set_name("w1");
diff --git a/chromium/ui/views/views_test_suite.cc b/chromium/ui/views/views_test_suite.cc
index e579a7d0503..1a3001c7bd8 100644
--- a/chromium/ui/views/views_test_suite.cc
+++ b/chromium/ui/views/views_test_suite.cc
@@ -22,6 +22,11 @@
#include "ui/aura/env.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "base/command_line.h"
+#include "ui/gl/gl_switches.h"
+#endif
+
namespace views {
ViewsTestSuite::ViewsTestSuite(int argc, char** argv)
@@ -43,6 +48,14 @@ int ViewsTestSuite::RunTestsSerially() {
void ViewsTestSuite::Initialize() {
base::TestSuite::Initialize();
+
+#if defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER)
+ // Force software-gl. This is necessary for mus tests to avoid an msan warning
+ // in gl init.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kOverrideUseSoftwareGLForTests);
+#endif
+
gl::GLSurfaceTestSupport::InitializeOneOff();
ui::RegisterPathProvider();
@@ -50,20 +63,20 @@ void ViewsTestSuite::Initialize() {
base::FilePath ui_test_pak_path;
ASSERT_TRUE(base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
-#if defined(USE_AURA)
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
InitializeEnv();
#endif
}
void ViewsTestSuite::Shutdown() {
-#if defined(USE_AURA)
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
DestroyEnv();
#endif
ui::ResourceBundle::CleanupSharedInstance();
base::TestSuite::Shutdown();
}
-#if defined(USE_AURA)
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
void ViewsTestSuite::InitializeEnv() {
env_ = aura::Env::CreateInstance();
}
diff --git a/chromium/ui/views/views_test_suite.h b/chromium/ui/views/views_test_suite.h
index bea4d2c914e..73654b3293f 100644
--- a/chromium/ui/views/views_test_suite.h
+++ b/chromium/ui/views/views_test_suite.h
@@ -30,14 +30,16 @@ class ViewsTestSuite : public base::TestSuite {
void Initialize() override;
void Shutdown() override;
-#if defined(USE_AURA)
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
// Different test suites may wish to create Env differently.
virtual void InitializeEnv();
virtual void DestroyEnv();
#endif
private:
-#if defined(USE_AURA)
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+ // On Chrome OS, aura::Env is set up in individual test fixtures, most notably
+ // ViewsTestBase.
std::unique_ptr<aura::Env> env_;
#endif
int argc_;
diff --git a/chromium/ui/views/widget/DEPS b/chromium/ui/views/widget/DEPS
deleted file mode 100644
index a244cf72baf..00000000000
--- a/chromium/ui/views/widget/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-specific_include_rules = {
- "widget_interactive_uitest\.cc": [
- "+mojo/core/embedder",
- ]
-}
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 45e70d362e2..da25e8ecf75 100644
--- a/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
@@ -97,6 +97,11 @@ class TestWidgetDelegate : public test::TestDesktopWidgetDelegate {
constexpr char TestWidgetDelegate::kAccessibleWindowTitle[];
+// This test framework uses the deprecated NSObject accessibility APIs - see
+// https://crbug.com/921109.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
class AXNativeWidgetMacTest : public test::WidgetTest {
public:
AXNativeWidgetMacTest() {}
@@ -927,3 +932,5 @@ TEST_F(AXNativeWidgetMacTest, Combobox) {
}
} // namespace views
+
+#pragma clang diagnostic pop
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index f0da4f88142..2ea5f107328 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -17,7 +17,7 @@
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
-#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
@@ -774,7 +774,7 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
actions.push_back(gfx::GetAtom(kXdndActionDirectSave));
ui::SetStringProperty(
xwindow_, gfx::GetAtom(kXdndDirectSave0),
- gfx::GetAtom(ui::Clipboard::kMimeTypeText),
+ gfx::GetAtom(ui::kMimeTypeText),
source_provider_->file_contents_name().AsUTF8Unsafe());
}
ui::SetAtomArrayProperty(xwindow_, kXdndActionList, "ATOM", actions);
@@ -1168,6 +1168,8 @@ void DesktopDragDropClientAuraX11::CompleteXdndPosition(
DragTranslate(screen_point, &data, &drop_target_event, &delegate);
if (delegate)
drag_operation = delegate->OnDragUpdated(*drop_target_event);
+ UMA_HISTOGRAM_BOOLEAN("Event.DragDrop.AcceptDragUpdate",
+ drag_operation != ui::DragDropTypes::DRAG_NONE);
// Sends an XdndStatus message back to the source_window. l[2,3]
// theoretically represent an area in the window where the current action is
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
index f60cc49e7ab..d0753adb6ad 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
@@ -363,10 +363,8 @@ void TestDragDropClient::SendXClientEvent(::Window xid, XEvent* event) {
class DesktopDragDropClientAuraX11Test : public ViewsTestBase {
public:
- DesktopDragDropClientAuraX11Test() {
- }
-
- ~DesktopDragDropClientAuraX11Test() override {}
+ DesktopDragDropClientAuraX11Test() = default;
+ ~DesktopDragDropClientAuraX11Test() override = default;
int StartDragAndDrop() {
ui::OSExchangeData data;
@@ -388,14 +386,14 @@ class DesktopDragDropClientAuraX11Test : public ViewsTestBase {
// ViewsTestBase:
void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+
ViewsTestBase::SetUp();
- test_views_delegate()->set_use_desktop_native_widgets(true);
// Create widget to initiate the drags.
widget_.reset(new 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();
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
index a9b86494fee..857523715ea 100644
--- 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
@@ -26,7 +26,7 @@ class FakeWmDragHandler;
// A fake handler, which initiates dragging.
class FakeWmDragHandler : public ui::WmDragHandler {
public:
- FakeWmDragHandler() : weak_ptr_factory_(this) {}
+ FakeWmDragHandler() = default;
~FakeWmDragHandler() override = default;
// ui::WmDragHandler
@@ -45,7 +45,7 @@ class FakeWmDragHandler : public ui::WmDragHandler {
private:
base::OnceCallback<void(int)> callback_;
- base::WeakPtrFactory<FakeWmDragHandler> weak_ptr_factory_;
+ base::WeakPtrFactory<FakeWmDragHandler> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(FakeWmDragHandler);
};
@@ -75,14 +75,14 @@ class DesktopDragDropClientOzoneTest : public ViewsTestBase {
// ViewsTestBase:
void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+
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();
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
index 094a0b00bce..d4c4cba5ac9 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
@@ -78,6 +78,9 @@ DWORD DesktopDropTargetWin::OnDragOver(IDataObject* data_object,
Translate(data_object, key_state, position, effect, &data, &event, &delegate);
if (delegate)
drag_operation = delegate->OnDragUpdated(*event);
+
+ UMA_HISTOGRAM_BOOLEAN("Event.DragDrop.AcceptDragUpdate",
+ drag_operation != ui::DragDropTypes::DRAG_NONE);
return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
}
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 a9b0444cf0f..d9396d0bb75 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
@@ -16,7 +16,7 @@ DesktopFocusRules::DesktopFocusRules(aura::Window* content_window)
DesktopFocusRules::~DesktopFocusRules() {}
-bool DesktopFocusRules::CanActivateWindow(aura::Window* window) const {
+bool DesktopFocusRules::CanActivateWindow(const aura::Window* window) const {
if (window && content_window_->GetRootWindow()->Contains(window) &&
wm::WindowStateIs(window->GetRootWindow(), ui::SHOW_STATE_MINIMIZED)) {
return true;
@@ -28,29 +28,30 @@ bool DesktopFocusRules::CanActivateWindow(aura::Window* window) const {
return !window || content_window_->GetRootWindow()->Contains(window);
}
-bool DesktopFocusRules::CanFocusWindow(aura::Window* window,
+bool DesktopFocusRules::CanFocusWindow(const 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 {
+bool DesktopFocusRules::SupportsChildActivation(
+ const aura::Window* window) const {
// In Desktop-Aura, only the content_window or children of the RootWindow are
// activatable.
return window->IsRootWindow();
}
bool DesktopFocusRules::IsWindowConsideredVisibleForActivation(
- aura::Window* window) const {
+ const aura::Window* window) const {
// |content_window_| is initially hidden and made visible from Show(). Even in
// this state we still want it to be active.
return BaseFocusRules::IsWindowConsideredVisibleForActivation(window) ||
(window == content_window_);
}
-aura::Window* DesktopFocusRules::GetToplevelWindow(
- aura::Window* window) const {
- aura::Window* top_level_window =
+const aura::Window* DesktopFocusRules::GetToplevelWindow(
+ const aura::Window* window) const {
+ const aura::Window* top_level_window =
wm::BaseFocusRules::GetToplevelWindow(window);
// In Desktop-Aura, only the content_window or children of the RootWindow are
// considered as top level windows.
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 96fc7f9b3b8..2fef6030d55 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
@@ -17,13 +17,14 @@ class DesktopFocusRules : public wm::BaseFocusRules {
private:
// Overridden from wm::BaseFocusRules:
- bool CanActivateWindow(aura::Window* window) const override;
- bool CanFocusWindow(aura::Window* window,
+ bool CanActivateWindow(const aura::Window* window) const override;
+ bool CanFocusWindow(const aura::Window* window,
const ui::Event* event) const override;
- bool SupportsChildActivation(aura::Window* window) const override;
+ bool SupportsChildActivation(const aura::Window* window) const override;
bool IsWindowConsideredVisibleForActivation(
- aura::Window* window) const override;
- aura::Window* GetToplevelWindow(aura::Window* window) const override;
+ const aura::Window* window) const override;
+ const aura::Window* GetToplevelWindow(
+ const aura::Window* window) const override;
aura::Window* GetNextActivatableWindow(aura::Window* window) const override;
// The content window. This is an activatable window even though it is a
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc
index 8b306f5e5ef..25694f34832 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc
@@ -8,37 +8,22 @@
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
-#include "ui/views/test/views_test_base.h"
+#include "ui/views/test/widget_test.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_util.h"
namespace views {
-namespace {
-
-std::unique_ptr<Widget> CreateDesktopWidget() {
- std::unique_ptr<Widget> widget(new Widget);
- Widget::InitParams params = Widget::InitParams(
- Widget::InitParams::TYPE_WINDOW);
- params.bounds = gfx::Rect(0, 0, 200, 200);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget = new DesktopNativeWidgetAura(widget.get());
- widget->Init(params);
- return widget;
-}
-
-} // namespace
-
-typedef ViewsTestBase DesktopFocusRulesTest;
+using DesktopFocusRulesTest = test::DesktopWidgetTest;
// Verifies we don't attempt to activate a window in another widget.
TEST_F(DesktopFocusRulesTest, DontFocusWindowsInOtherHierarchies) {
// Two widgets (each with a DesktopNativeWidgetAura). |w2| has a child Window
// |w2_child| that is not focusable. |w2_child|'s has a transient parent in
// |w1|.
- std::unique_ptr<views::Widget> w1(CreateDesktopWidget());
- std::unique_ptr<views::Widget> w2(CreateDesktopWidget());
+ Widget* w1 = CreateTopLevelNativeWidget();
+ Widget* w2 = CreateTopLevelNativeWidget();
aura::test::TestWindowDelegate w2_child_delegate;
w2_child_delegate.set_can_focus(false);
aura::Window* w2_child = new aura::Window(&w2_child_delegate);
@@ -50,8 +35,9 @@ TEST_F(DesktopFocusRulesTest, DontFocusWindowsInOtherHierarchies) {
aura::client::GetFocusClient(w2->GetNativeView())->GetFocusedWindow();
EXPECT_TRUE((focused == NULL) || w2->GetNativeView()->Contains(focused));
wm::RemoveTransientChild(w1->GetNativeView(), w2_child);
- w1.reset();
- w2.reset();
+
+ w1->CloseNow();
+ w2->CloseNow();
}
} // namespace views
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 252001f8731..00157394710 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
@@ -23,7 +23,6 @@
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/compositor/layer.h"
-#include "ui/display/screen.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/rect.h"
@@ -83,6 +82,7 @@ class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver {
static aura::Window* CreateParentWindow(aura::Window* child_window,
const gfx::Rect& bounds,
bool full_screen,
+ bool is_menu,
bool root_is_always_on_top) {
// This instance will get deleted when the widget is destroyed.
DesktopNativeWidgetTopLevelHandler* top_level_handler =
@@ -91,8 +91,9 @@ class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver {
child_window->SetBounds(gfx::Rect(bounds.size()));
Widget::InitParams init_params;
- init_params.type = full_screen ? Widget::InitParams::TYPE_WINDOW :
- Widget::InitParams::TYPE_POPUP;
+ init_params.type = full_screen ? Widget::InitParams::TYPE_WINDOW
+ : is_menu ? Widget::InitParams::TYPE_MENU
+ : Widget::InitParams::TYPE_POPUP;
init_params.bounds = bounds;
init_params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
init_params.layer_type = ui::LAYER_NOT_DRAWN;
@@ -198,7 +199,7 @@ class DesktopNativeWidgetAuraWindowParentingClient
root_is_always_on_top = native_widget->IsAlwaysOnTop();
return DesktopNativeWidgetTopLevelHandler::CreateParentWindow(
- window, bounds, is_fullscreen, root_is_always_on_top);
+ window, bounds, is_fullscreen, is_menu, root_is_always_on_top);
}
return root_window_;
}
@@ -726,11 +727,7 @@ std::string DesktopNativeWidgetAura::GetWorkspace() const {
void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
if (!content_window_)
return;
- aura::Window* root = host_->window();
- display::Screen* screen = display::Screen::GetScreen();
- gfx::Rect bounds_in_pixels = screen->DIPToScreenRectInWindow(root, bounds);
- desktop_window_tree_host_->AsWindowTreeHost()->SetBoundsInPixels(
- bounds_in_pixels);
+ desktop_window_tree_host_->SetBoundsInDIP(bounds);
}
void DesktopNativeWidgetAura::SetBoundsConstrained(const gfx::Rect& bounds) {
@@ -851,6 +848,9 @@ void DesktopNativeWidgetAura::Maximize() {
void DesktopNativeWidgetAura::Minimize() {
if (content_window_)
desktop_window_tree_host_->Minimize();
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(GetWidget()->GetRootView());
+ root_view->ResetEventHandlers();
}
bool DesktopNativeWidgetAura::IsMaximized() const {
@@ -1005,10 +1005,6 @@ void DesktopNativeWidgetAura::OnSizeConstraintsChanged() {
desktop_window_tree_host_->SizeConstraintsChanged();
}
-void DesktopNativeWidgetAura::RepostNativeEvent(gfx::NativeEvent native_event) {
- OnEvent(native_event);
-}
-
std::string DesktopNativeWidgetAura::GetName() const {
return name_;
}
@@ -1073,7 +1069,7 @@ bool DesktopNativeWidgetAura::HasHitTestMask() const {
return native_widget_delegate_->HasHitTestMask();
}
-void DesktopNativeWidgetAura::GetHitTestMask(gfx::Path* mask) const {
+void DesktopNativeWidgetAura::GetHitTestMask(SkPath* mask) const {
native_widget_delegate_->GetHitTestMask(mask);
}
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 0189e561625..8e85a951c4c 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
@@ -188,7 +188,6 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
bool IsTranslucentWindowOpacitySupported() const override;
ui::GestureRecognizer* GetGestureRecognizer() override;
void OnSizeConstraintsChanged() override;
- void RepostNativeEvent(gfx::NativeEvent native_event) override;
std::string GetName() const override;
// Overridden from aura::WindowDelegate:
@@ -210,7 +209,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
void OnWindowDestroyed(aura::Window* window) override;
void OnWindowTargetVisibilityChanged(bool visible) override;
bool HasHitTestMask() const override;
- void GetHitTestMask(gfx::Path* mask) const override;
+ void GetHitTestMask(SkPath* mask) const override;
// Overridden from ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
index ae3193c3304..ecac0298e94 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
@@ -43,7 +43,7 @@
namespace views {
namespace test {
-typedef ViewsTestBase DesktopNativeWidgetAuraTest;
+using DesktopNativeWidgetAuraTest = DesktopWidgetTest;
// Verifies creating a Widget with a parent that is not in a RootWindow doesn't
// crash.
@@ -55,7 +55,6 @@ TEST_F(DesktopNativeWidgetAuraTest, CreateWithParentNotInRootWindow) {
params.bounds = gfx::Rect(0, 0, 200, 200);
params.parent = window.get();
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget = new DesktopNativeWidgetAura(&widget);
widget.Init(params);
}
@@ -75,7 +74,6 @@ TEST_F(DesktopNativeWidgetAuraTest, DesktopAuraWindowSizeTest) {
#endif
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
widget.Init(init_params);
gfx::Rect bounds(0, 0, 100, 100);
@@ -104,7 +102,6 @@ TEST_F(DesktopNativeWidgetAuraTest, NativeViewInitiallyHidden) {
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
widget.Init(init_params);
EXPECT_FALSE(widget.GetNativeView()->IsVisible());
}
@@ -115,12 +112,10 @@ TEST_F(DesktopNativeWidgetAuraTest, NativeViewNoActivate) {
Widget widget;
Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- DesktopNativeWidgetAura* widget_aura = new DesktopNativeWidgetAura(&widget);
- init_params.native_widget = widget_aura;
widget.Init(init_params);
EXPECT_FALSE(widget.CanActivate());
- EXPECT_EQ(nullptr, aura::client::GetFocusClient(widget_aura->content_window())
+ EXPECT_EQ(nullptr, aura::client::GetFocusClient(widget.GetNativeWindow())
->GetFocusedWindow());
}
@@ -132,7 +127,6 @@ TEST_F(DesktopNativeWidgetAuraTest, WidgetNotVisibleOnlyWindowTreeHostShown) {
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
widget.Init(init_params);
ShowWindow(widget.GetNativeView()->GetHost()->GetAcceleratedWidget(),
SW_SHOWNORMAL);
@@ -145,7 +139,6 @@ TEST_F(DesktopNativeWidgetAuraTest, DesktopAuraWindowShowFrameless) {
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
widget.Init(init_params);
// Make sure that changing frame type doesn't crash when there's no non-client
@@ -165,31 +158,32 @@ TEST_F(DesktopNativeWidgetAuraTest, DesktopAuraWindowShowFrameless) {
#endif // OS_WIN
}
+#if defined(OS_CHROMEOS)
+// TODO(crbug.com/916272): investigate fixing and enabling on Chrome OS.
+#define MAYBE_GlobalCursorState DISABLED_GlobalCursorState
+#else
+#define MAYBE_GlobalCursorState GlobalCursorState
+#endif
+
// Verify that the cursor state is shared between two native widgets.
-TEST_F(DesktopNativeWidgetAuraTest, GlobalCursorState) {
+TEST_F(DesktopNativeWidgetAuraTest, MAYBE_GlobalCursorState) {
// Create two native widgets, each owning different root windows.
Widget widget_a;
Widget::InitParams init_params_a =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params_a.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- DesktopNativeWidgetAura* desktop_native_widget_aura_a =
- new DesktopNativeWidgetAura(&widget_a);
- init_params_a.native_widget = desktop_native_widget_aura_a;
widget_a.Init(init_params_a);
Widget widget_b;
Widget::InitParams init_params_b =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params_b.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- DesktopNativeWidgetAura* desktop_native_widget_aura_b =
- new DesktopNativeWidgetAura(&widget_b);
- init_params_b.native_widget = desktop_native_widget_aura_b;
widget_b.Init(init_params_b);
aura::client::CursorClient* cursor_client_a = aura::client::GetCursorClient(
- desktop_native_widget_aura_a->host()->window());
+ widget_a.GetNativeView()->GetHost()->window());
aura::client::CursorClient* cursor_client_b = aura::client::GetCursorClient(
- desktop_native_widget_aura_b->host()->window());
+ widget_b.GetNativeView()->GetHost()->window());
// Verify the cursor can be locked using one client and unlocked using
// another.
@@ -270,9 +264,6 @@ TEST_F(DesktopNativeWidgetAuraTest, DontAccessContentWindowDuringDestruction) {
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- DesktopNativeWidgetAura* desktop_native_widget_aura =
- new DesktopNativeWidgetAura(&widget);
- init_params.native_widget = desktop_native_widget_aura;
widget.Init(init_params);
// Owned by |widget|.
@@ -288,10 +279,12 @@ TEST_F(DesktopNativeWidgetAuraTest, DontAccessContentWindowDuringDestruction) {
namespace {
std::unique_ptr<Widget> CreateAndShowControlWidget(aura::Window* parent) {
+ auto widget = std::make_unique<Widget>();
Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.parent = parent;
- auto widget = std::make_unique<Widget>();
+ params.native_widget = CreatePlatformNativeWidgetImpl(params, widget.get(),
+ kStubCapture, nullptr);
widget->Init(params);
widget->Show();
return widget;
@@ -299,15 +292,20 @@ std::unique_ptr<Widget> CreateAndShowControlWidget(aura::Window* parent) {
} // namespace
-TEST_F(DesktopNativeWidgetAuraTest, ReorderDoesntRecomputeOcclusion) {
+#if defined(OS_CHROMEOS)
+// TODO(crbug.com/916272): investigate fixing and enabling on Chrome OS.
+#define MAYBE_ReorderDoesntRecomputeOcclusion \
+ DISABLED_ReorderDoesntRecomputeOcclusion
+#else
+#define MAYBE_ReorderDoesntRecomputeOcclusion ReorderDoesntRecomputeOcclusion
+#endif
+
+TEST_F(DesktopNativeWidgetAuraTest, MAYBE_ReorderDoesntRecomputeOcclusion) {
// Create the parent widget.
Widget parent;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- DesktopNativeWidgetAura* desktop_native_widget_aura =
- new DesktopNativeWidgetAura(&parent);
- init_params.native_widget = desktop_native_widget_aura;
parent.Init(init_params);
parent.Show();
@@ -355,7 +353,6 @@ TEST_F(DesktopNativeWidgetAuraTest, WidgetCanBeDestroyedFromNestedLoop) {
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget = new DesktopNativeWidgetAura(widget.get());
widget->Init(params);
widget->Show();
@@ -483,18 +480,7 @@ class DesktopAuraTopLevelWindowTest : public aura::WindowObserver {
DISALLOW_COPY_AND_ASSIGN(DesktopAuraTopLevelWindowTest);
};
-class DesktopAuraWidgetTest : public WidgetTest {
- public:
- DesktopAuraWidgetTest() {}
-
- void SetUp() override {
- ViewsTestBase::SetUp();
- test_views_delegate()->set_use_desktop_native_widgets(true);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DesktopAuraWidgetTest);
-};
+using DesktopAuraWidgetTest = DesktopWidgetTest;
TEST_F(DesktopAuraWidgetTest, FullscreenWindowDestroyedBeforeOwnerTest) {
DesktopAuraTopLevelWindowTest fullscreen_window;
@@ -615,8 +601,6 @@ void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
Widget* widget = new Widget;
Widget::InitParams params =
test->CreateParams(Widget::InitParams::TYPE_POPUP);
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, widget, nullptr);
params.bounds = gfx::Rect(0, 0, 50, 100);
widget->Init(params);
widget->SetContentsView(new CloseWidgetView(last_event_type));
@@ -651,9 +635,16 @@ class ModalDialogDelegate : public DialogDelegateView {
} // namespace
+#if defined(OS_CHROMEOS)
+// TODO(crbug.com/916272): investigate fixing and enabling on Chrome OS.
+#define MAYBE_WindowMouseModalityTest DISABLED_WindowMouseModalityTest
+#else
+#define MAYBE_WindowMouseModalityTest WindowMouseModalityTest
+#endif
+
// This test verifies that whether mouse events when a modal dialog is
// displayed are eaten or recieved by the dialog.
-TEST_F(WidgetTest, WindowMouseModalityTest) {
+TEST_F(DesktopWidgetTest, MAYBE_WindowMouseModalityTest) {
// Create a top level widget.
Widget top_level_widget;
Widget::InitParams init_params =
@@ -662,8 +653,6 @@ TEST_F(WidgetTest, WindowMouseModalityTest) {
gfx::Rect initial_bounds(0, 0, 500, 500);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- init_params, &top_level_widget, nullptr);
top_level_widget.Init(init_params);
top_level_widget.Show();
EXPECT_TRUE(top_level_widget.IsVisible());
@@ -726,7 +715,7 @@ TEST_F(WidgetTest, WindowMouseModalityTest) {
#if defined(OS_WIN)
// Tests whether we can activate the top level widget when a modal dialog is
// active.
-TEST_F(WidgetTest, WindowModalityActivationTest) {
+TEST_F(DesktopWidgetTest, WindowModalityActivationTest) {
TestDesktopWidgetDelegate widget_delegate;
widget_delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
@@ -764,11 +753,9 @@ TEST_F(WidgetTest, WindowModalityActivationTest) {
// messages via the WindowEventTarget interface implemented by the
// HWNDMessageHandler class does not cause a crash due to an unprocessed
// event
-TEST_F(WidgetTest, CharMessagesAsKeyboardMessagesDoesNotCrash) {
+TEST_F(DesktopWidgetTest, CharMessagesAsKeyboardMessagesDoesNotCrash) {
Widget widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, &widget, nullptr);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(params);
widget.Show();
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
index 2f583ce9719..da3f2732b7c 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
@@ -38,12 +38,13 @@ void DesktopScreenPositionClient::SetBounds(aura::Window* window,
// TODO(jam): Use the 3rd parameter, |display|.
aura::Window* root = window->GetRootWindow();
- // This method assumes that |window| does not have an associated
- // DesktopNativeWidgetAura.
internal::NativeWidgetPrivate* desktop_native_widget =
DesktopNativeWidgetAura::ForWindow(root);
- DCHECK(!desktop_native_widget ||
- desktop_native_widget->GetNativeView() != window);
+ if (desktop_native_widget &&
+ desktop_native_widget->GetNativeView() == window) {
+ desktop_native_widget->SetBounds(bounds);
+ return;
+ }
if (PositionWindowInScreenCoordinates(window)) {
// The caller expects windows we consider "embedded" to be placed in the
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.cc
new file mode 100644
index 00000000000..6125dbe8fdb
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.cc
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/display/screen.h"
+
+namespace views {
+
+void DesktopWindowTreeHost::SetBoundsInDIP(const gfx::Rect& bounds) {
+ aura::Window* root = AsWindowTreeHost()->window();
+ const gfx::Rect bounds_in_pixels =
+ display::Screen::GetScreen()->DIPToScreenRectInWindow(root, bounds);
+ AsWindowTreeHost()->SetBoundsInPixels(bounds_in_pixels);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h
index 8a909991f7d..a0ec5893a39 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h
@@ -187,6 +187,10 @@ class VIEWS_EXPORT DesktopWindowTreeHost {
// Returns whether a VisibilityController should be created.
virtual bool ShouldCreateVisibilityController() const = 0;
+
+ // Sets the bounds in screen coordinate DIPs (WindowTreeHost generally
+ // operates in pixels). This function is implemented in terms of Screen.
+ virtual void SetBoundsInDIP(const gfx::Rect& bounds);
};
} // namespace views
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 72d04d0595b..ab1c54e75ca 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
@@ -72,14 +72,6 @@ DesktopWindowTreeHostPlatform::~DesktopWindowTreeHostPlatform() {
DestroyDispatcher();
}
-void DesktopWindowTreeHostPlatform::SetBoundsInDIP(
- const gfx::Rect& bounds_in_dip) {
- DCHECK_NE(0, device_scale_factor());
- SetBoundsInPixels(
- gfx::ConvertRectToPixel(device_scale_factor(), bounds_in_dip),
- viz::LocalSurfaceIdAllocation());
-}
-
void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
ui::PlatformWindowInitProperties properties =
ConvertWidgetInitParamsToInitProperties(params);
@@ -95,7 +87,7 @@ void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
const Widget::InitParams& params) {
- native_widget_delegate_->OnNativeWidgetCreated(true);
+ native_widget_delegate_->OnNativeWidgetCreated();
#if defined(OS_LINUX)
// Setup a non_client_window_event_filter, which handles resize/move, double
@@ -422,6 +414,12 @@ void DesktopWindowTreeHostPlatform::SetOpacity(float opacity) {
NOTIMPLEMENTED_LOG_ONCE();
}
+void DesktopWindowTreeHostPlatform::SetAspectRatio(
+ const gfx::SizeF& aspect_ratio) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
void DesktopWindowTreeHostPlatform::SetWindowIcons(
const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
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 fa106717dc2..02f30ef40ca 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
@@ -24,8 +24,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
DesktopNativeWidgetAura* desktop_native_widget_aura);
~DesktopWindowTreeHostPlatform() override;
- void SetBoundsInDIP(const gfx::Rect& bounds_in_dip);
-
// DesktopWindowTreeHost:
void Init(const Widget::InitParams& params) override;
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
@@ -80,7 +78,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
void SetFullscreen(bool fullscreen) override;
bool IsFullscreen() const override;
void SetOpacity(float opacity) override;
- void SetAspectRatio(const gfx::SizeF& aspect_ratio) override {}
+ void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) override;
void InitModalType(ui::ModalType modal_type) override;
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 c16d7368315..e43193ea912 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
@@ -6,6 +6,7 @@
#include "base/containers/flat_set.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/aura/client/aura_constants.h"
@@ -26,7 +27,6 @@
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/path_win.h"
#include "ui/views/corewm/tooltip_win.h"
#include "ui/views/views_switches.h"
@@ -717,7 +717,7 @@ int DesktopWindowTreeHostWin::GetNonClientComponent(
}
void DesktopWindowTreeHostWin::GetWindowMask(const gfx::Size& size,
- gfx::Path* path) {
+ SkPath* path) {
if (GetWidget()->non_client_view()) {
GetWidget()->non_client_view()->GetWindowMask(size, path);
} else if (!window_enlargement_.IsZero()) {
@@ -809,7 +809,7 @@ void DesktopWindowTreeHostWin::HandleAccelerator(
}
void DesktopWindowTreeHostWin::HandleCreate() {
- native_widget_delegate_->OnNativeWidgetCreated(true);
+ native_widget_delegate_->OnNativeWidgetCreated();
}
void DesktopWindowTreeHostWin::HandleDestroying() {
@@ -861,6 +861,23 @@ void DesktopWindowTreeHostWin::HandleVisibilityChanged(bool visible) {
native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible);
}
+void DesktopWindowTreeHostWin::HandleWindowMinimizedOrRestored(bool restored) {
+ // Ignore minimize/restore events that happen before widget initialization is
+ // done. If a window is created minimized, and then activated, restoring
+ // focus will fail because the root window is not visible, which is exposed by
+ // ExtensionWindowCreateTest.AcceptState.
+ if (!native_widget_delegate_->IsNativeWidgetInitialized())
+ return;
+
+ if (restored)
+ window()->Show();
+ else
+ window()->Hide();
+
+ if (compositor())
+ compositor()->SetVisible(restored);
+}
+
void DesktopWindowTreeHostWin::HandleClientSizeChanged(
const gfx::Size& new_size) {
CheckForMonitorChange();
@@ -885,9 +902,13 @@ void DesktopWindowTreeHostWin::HandleNativeBlur(HWND focused_window) {
}
bool DesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* 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.
+ // Mouse events in occluded windows should be very rare. If this stat isn't
+ // very close to 0, that would indicate that windows are incorrectly getting
+ // marked occluded, or getting stuck in the occluded state. Event can cause
+ // this object to be deleted so check occlusion state before we do anything
+ // with the event.
+ if (window()->occlusion_state() == aura::Window::OcclusionState::OCCLUDED)
+ UMA_HISTOGRAM_BOOLEAN("OccludedWindowMouseEvents", true);
SendEventToSink(event);
return event->handled();
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
index ecb84e76ae2..57fdabdb047 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
@@ -169,7 +169,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
int GetInitialShowState() const override;
bool WillProcessWorkAreaChange() const override;
int GetNonClientComponent(const gfx::Point& point) const override;
- void GetWindowMask(const gfx::Size& size, gfx::Path* path) override;
+ void GetWindowMask(const gfx::Size& size, SkPath* path) override;
bool GetClientAreaInsets(gfx::Insets* insets,
HMONITOR monitor) const override;
bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const override;
@@ -197,6 +197,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void HandleWorkAreaChanged() override;
void HandleVisibilityChanging(bool visible) override;
void HandleVisibilityChanged(bool visible) override;
+ void HandleWindowMinimizedOrRestored(bool restored) override;
void HandleClientSizeChanged(const gfx::Size& new_size) override;
void HandleFrameChanged() override;
void HandleNativeFocus(HWND last_focused_window) override;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 5e46a4f6908..bd2f435da5b 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
@@ -9,8 +9,8 @@
#include "base/command_line.h"
#include "base/containers/flat_set.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -45,7 +45,6 @@
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/path_x11.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
@@ -429,7 +428,7 @@ void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
SetWindowTransparency();
- native_widget_delegate_->OnNativeWidgetCreated(true);
+ native_widget_delegate_->OnNativeWidgetCreated();
}
void DesktopWindowTreeHostX11::OnWidgetInitDone() {}
@@ -518,7 +517,7 @@ void DesktopWindowTreeHostX11::Show(ui::WindowShowState show_state,
if (compositor())
SetVisible(true);
- if (!IsVisible())
+ if (!window_mapped_in_client_ || IsMinimized())
MapWindow(show_state);
switch (show_state) {
@@ -547,7 +546,10 @@ void DesktopWindowTreeHostX11::Show(ui::WindowShowState show_state,
}
bool DesktopWindowTreeHostX11::IsVisible() const {
- return window_mapped_in_client_ && !IsMinimized();
+ // On Windows, IsVisible() returns true for minimized windows. On X11, a
+ // minimized window is not mapped, so an explicit IsMinimized() check is
+ // necessary.
+ return window_mapped_in_client_ || IsMinimized();
}
void DesktopWindowTreeHostX11::SetSize(const gfx::Size& requested_size) {
@@ -762,7 +764,6 @@ void DesktopWindowTreeHostX11::Activate() {
// after an Activate(), so just set this state now.
has_pointer_focus_ = false;
has_window_focus_ = true;
- // window_mapped_in_client_ == true based on the IsVisible() check above.
window_mapped_in_server_ = true;
XSetErrorHandler(old_error_handler);
}
@@ -816,7 +817,7 @@ void DesktopWindowTreeHostX11::Maximize() {
// Some WMs do not respect maximization hints on unmapped windows, so we
// save this one for later too.
- should_maximize_after_map_ = !IsVisible();
+ should_maximize_after_map_ = !window_mapped_in_client_;
// When we are in the process of requesting to maximize a window, we can
// accurately keep track of our restored bounds instead of relying on the
@@ -1582,7 +1583,7 @@ void DesktopWindowTreeHostX11::InitX11Window(
const unsigned char kDarkGtkThemeVariant[] = "dark";
XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_GTK_THEME_VARIANT"),
gfx::GetAtom("UTF8_STRING"), 8, PropModeReplace,
- kDarkGtkThemeVariant, arraysize(kDarkGtkThemeVariant) - 1);
+ kDarkGtkThemeVariant, base::size(kDarkGtkThemeVariant) - 1);
}
// Always composite Chromium windows if a compositing WM is used. Sometimes,
@@ -1877,7 +1878,7 @@ void DesktopWindowTreeHostX11::ResetWindowRegion() {
window_shape_.reset();
if (!IsMaximized() && !IsFullscreen()) {
- gfx::Path window_mask;
+ SkPath window_mask;
Widget* widget = native_widget_delegate_->AsWidget();
if (widget->non_client_view()) {
// Some frame views define a custom (non-rectangular) window mask. If
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 e25fab221ed..eb61fb36b46 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
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
@@ -21,7 +22,6 @@
#include "ui/events/test/platform_event_source_test_api.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/views/test/views_test_base.h"
@@ -85,7 +85,7 @@ class ShapedNonClientFrameView : public NonClientFrameView {
return HTBOTTOM;
return HTNOWHERE;
}
- void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {
int right = size.width();
int bottom = size.height();
@@ -129,7 +129,6 @@ std::unique_ptr<Widget> CreateWidget(WidgetDelegate* delegate) {
params.delegate = delegate;
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.remove_standard_frame = true;
- params.native_widget = new DesktopNativeWidgetAura(widget.get());
params.bounds = gfx::Rect(100, 100, 100, 100);
widget->Init(params);
return widget;
@@ -178,6 +177,8 @@ class DesktopWindowTreeHostX11Test : public ViewsTestBase {
~DesktopWindowTreeHostX11Test() override {}
void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+
std::vector<int> pointer_devices;
pointer_devices.push_back(kPointerDeviceId);
ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(pointer_devices);
@@ -371,7 +372,6 @@ TEST_F(DesktopWindowTreeHostX11Test, ToggleMinimizePropogateToContentWindow) {
Widget widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget = new DesktopNativeWidgetAura(&widget);
widget.Init(params);
widget.Show();
ui::X11EventSource::GetInstance()->DispatchXEvents();
@@ -431,7 +431,6 @@ TEST_F(DesktopWindowTreeHostX11Test, ChildWindowDestructionDuringTearDown) {
Widget::InitParams parent_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- parent_params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
parent_widget.Init(parent_params);
parent_widget.Show();
ui::X11EventSource::GetInstance()->DispatchXEvents();
@@ -440,7 +439,6 @@ TEST_F(DesktopWindowTreeHostX11Test, ChildWindowDestructionDuringTearDown) {
Widget::InitParams child_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- child_params.native_widget = new DesktopNativeWidgetAura(&child_widget);
child_params.parent = parent_widget.GetNativeWindow();
child_widget.Init(child_params);
child_widget.Show();
@@ -477,7 +475,6 @@ TEST_F(DesktopWindowTreeHostX11Test, SetBoundsWithMinMax) {
CustomSizeWidget widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget = new DesktopNativeWidgetAura(&widget);
params.bounds = gfx::Rect(200, 100);
widget.Init(params);
widget.Show();
@@ -551,7 +548,6 @@ TEST_F(DesktopWindowTreeHostX11HighDPITest,
Widget first;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget = new DesktopNativeWidgetAura(&first);
params.bounds = gfx::Rect(0, 0, 50, 50);
first.Init(params);
first.Show();
@@ -559,7 +555,6 @@ TEST_F(DesktopWindowTreeHostX11HighDPITest,
Widget second;
params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget = new DesktopNativeWidgetAura(&second);
params.bounds = gfx::Rect(50, 50, 50, 50);
second.Init(params);
second.Show();
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
index a688da8c12b..2d3e6a3fac2 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
@@ -10,13 +10,11 @@
#include <memory>
#include <vector>
-#include "base/macros.h"
#include "base/stl_util.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/path_x11.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
@@ -215,7 +213,7 @@ TEST_F(X11TopmostWindowFinderTest, Basic) {
XID xid3 = window3->GetHost()->GetAcceleratedWidget();
XID xids[] = { xid1, xid2, xid3 };
- StackingClientListWaiter waiter(xids, arraysize(xids));
+ StackingClientListWaiter waiter(xids, base::size(xids));
waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
@@ -258,7 +256,7 @@ TEST_F(X11TopmostWindowFinderTest, Minimized) {
XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
XID xids[] = { xid1, xid2 };
- StackingClientListWaiter stack_waiter(xids, arraysize(xids));
+ StackingClientListWaiter stack_waiter(xids, base::size(xids));
stack_waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
@@ -307,7 +305,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangular) {
XShapeCombineRegion(xdisplay(), xid2, ShapeBounding, 0, 0, region2.get(),
false);
XID xids[] = { xid1, xid2 };
- StackingClientListWaiter stack_waiter(xids, arraysize(xids));
+ StackingClientListWaiter stack_waiter(xids, base::size(xids));
stack_waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
@@ -338,7 +336,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) {
widget1->SetShape(std::move(shape1));
XID xids[] = { xid1 };
- StackingClientListWaiter stack_waiter(xids, arraysize(xids));
+ StackingClientListWaiter stack_waiter(xids, base::size(xids));
stack_waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
@@ -361,7 +359,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularNullShape) {
widget1->SetShape(nullptr);
XID xids[] = { xid1 };
- StackingClientListWaiter stack_waiter(xids, arraysize(xids));
+ StackingClientListWaiter stack_waiter(xids, base::size(xids));
stack_waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
@@ -395,7 +393,7 @@ TEST_F(X11TopmostWindowFinderTest, Menu) {
// |menu_xid| is never added to _NET_CLIENT_LIST_STACKING.
XID xids[] = { xid };
- StackingClientListWaiter stack_waiter(xids, arraysize(xids));
+ StackingClientListWaiter stack_waiter(xids, base::size(xids));
stack_waiter.Wait();
EXPECT_EQ(xid, FindTopmostXWindowAt(110, 110));
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 e65fba7f97f..038f3ca5163 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
@@ -9,10 +9,10 @@
#include "base/bind.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/env.h"
@@ -222,7 +222,7 @@ void X11WholeScreenMoveLoop::EndMoveLoop() {
XDisplay* display = gfx::GetXDisplay();
unsigned int esc_keycode = XKeysymToKeycode(display, XK_Escape);
- for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
+ for (size_t i = 0; i < base::size(kModifiersMasks); ++i) {
XUngrabKey(display, esc_keycode, kModifiersMasks[i], grab_input_window_);
}
@@ -254,7 +254,7 @@ bool X11WholeScreenMoveLoop::GrabPointer(gfx::NativeCursor cursor) {
void X11WholeScreenMoveLoop::GrabEscKey() {
XDisplay* display = gfx::GetXDisplay();
unsigned int esc_keycode = XKeysymToKeycode(display, XK_Escape);
- for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
+ for (size_t i = 0; i < base::size(kModifiersMasks); ++i) {
XGrabKey(display, esc_keycode, kModifiersMasks[i], grab_input_window_,
x11::False, GrabModeAsync, GrabModeAsync);
}
diff --git a/chromium/ui/views/widget/desktop_widget_unittest.cc b/chromium/ui/views/widget/desktop_widget_unittest.cc
index 0ab25f179c2..6e17ae35593 100644
--- a/chromium/ui/views/widget/desktop_widget_unittest.cc
+++ b/chromium/ui/views/widget/desktop_widget_unittest.cc
@@ -5,14 +5,13 @@
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/views/test/native_widget_factory.h"
-#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
namespace views {
-typedef ViewsTestBase DesktopScreenPositionClientTest;
+using DesktopScreenPositionClientTest = test::DesktopWidgetTest;
// Verifies setting the bounds of a dialog parented to a Widget with a
// PlatformDesktopNativeWidget is positioned correctly.
@@ -21,8 +20,6 @@ TEST_F(DesktopScreenPositionClientTest, PositionDialog) {
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(10, 11, 200, 200);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget = test::CreatePlatformDesktopNativeWidgetImpl(
- params, &parent_widget, nullptr);
parent_widget.Init(params);
// Owned by |dialog|.
@@ -60,8 +57,6 @@ TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) {
origin + work_area.OffsetFromOrigin(),
gfx::Size(700, work_area.height() - origin.y() - work_area.y()));
params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params1.native_widget =
- test::CreatePlatformDesktopNativeWidgetImpl(params1, &widget1, nullptr);
widget1.Init(params1);
Widget::InitParams params2 =
@@ -70,6 +65,8 @@ TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) {
params2.parent = widget1.GetNativeView();
params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params2.child = true;
+ params2.native_widget = test::CreatePlatformNativeWidgetImpl(
+ params2, &widget2, test::kStubCapture, nullptr);
widget2.Init(params2);
Widget::InitParams params3 =
@@ -78,6 +75,8 @@ TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) {
params3.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params3.child = true;
params3.bounds = gfx::Rect(origin, gfx::Size(500, work_area.height() - 200));
+ params3.native_widget = test::CreatePlatformNativeWidgetImpl(
+ params3, &widget3, test::kStubCapture, nullptr);
widget3.Init(params3);
// The origin of the 3rd window should be the sum of all parent origins.
@@ -107,8 +106,6 @@ TEST_F(DesktopScreenPositionClientTest, InitialBoundsConstrainedToDesktop) {
params.bounds = gfx::Rect(
origin, gfx::Size(work_area.width() / 2, work_area.height() / 2));
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.native_widget =
- test::CreatePlatformDesktopNativeWidgetImpl(params, &widget, nullptr);
widget.Init(params);
// The bounds of the window should be fully on the primary display.
@@ -141,8 +138,6 @@ TEST_F(DesktopScreenPositionClientTest, InitialBoundsConstrainedToParent) {
params1.bounds = gfx::Rect(
origin, gfx::Size(work_area.width() / 2, work_area.height() / 2));
params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params1.native_widget =
- test::CreatePlatformDesktopNativeWidgetImpl(params1, &widget1, nullptr);
widget1.Init(params1);
gfx::Rect widget_bounds(widget1.GetWindowBoundsInScreen());
@@ -154,6 +149,8 @@ TEST_F(DesktopScreenPositionClientTest, InitialBoundsConstrainedToParent) {
params2.parent = widget1.GetNativeView();
params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params2.child = true;
+ params2.native_widget = test::CreatePlatformNativeWidgetImpl(
+ params2, &widget2, test::kStubCapture, nullptr);
widget2.Init(params2);
// The bounds of the child window should be fully in the parent.
diff --git a/chromium/ui/views/widget/drop_helper.cc b/chromium/ui/views/widget/drop_helper.cc
index f201f7311bd..62f39b691fc 100644
--- a/chromium/ui/views/widget/drop_helper.cc
+++ b/chromium/ui/views/widget/drop_helper.cc
@@ -102,7 +102,7 @@ View* DropHelper::CalculateTargetViewImpl(
}
#else
int formats = 0;
- std::set<ui::Clipboard::FormatType> format_types;
+ std::set<ui::ClipboardFormatType> format_types;
while (view && view != target_view_) {
if (view->enabled() &&
view->GetDropFormats(&formats, &format_types) &&
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index 63ef7767c60..9559f5a32b5 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -179,7 +179,7 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
if (params.type == Widget::InitParams::TYPE_CONTROL)
window_->Show();
- delegate_->OnNativeWidgetCreated(false);
+ delegate_->OnNativeWidgetCreated();
gfx::Rect window_bounds = params.bounds;
gfx::NativeView parent = params.parent;
@@ -814,10 +814,6 @@ void NativeWidgetAura::OnSizeConstraintsChanged() {
window_->SetProperty(aura::client::kResizeBehaviorKey, behavior);
}
-void NativeWidgetAura::RepostNativeEvent(gfx::NativeEvent native_event) {
- OnEvent(native_event);
-}
-
std::string NativeWidgetAura::GetName() const {
return window_ ? window_->GetName() : std::string();
}
@@ -913,7 +909,7 @@ bool NativeWidgetAura::HasHitTestMask() const {
return delegate_->HasHitTestMask();
}
-void NativeWidgetAura::GetHitTestMask(gfx::Path* mask) const {
+void NativeWidgetAura::GetHitTestMask(SkPath* mask) const {
DCHECK(mask);
delegate_->GetHitTestMask(mask);
}
diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h
index 768f0bde976..c708ebc7080 100644
--- a/chromium/ui/views/widget/native_widget_aura.h
+++ b/chromium/ui/views/widget/native_widget_aura.h
@@ -149,7 +149,6 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate,
bool IsTranslucentWindowOpacitySupported() const override;
ui::GestureRecognizer* GetGestureRecognizer() override;
void OnSizeConstraintsChanged() override;
- void RepostNativeEvent(gfx::NativeEvent native_event) override;
std::string GetName() const override;
// Overridden from aura::WindowDelegate:
@@ -171,7 +170,7 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate,
void OnWindowDestroyed(aura::Window* window) override;
void OnWindowTargetVisibilityChanged(bool visible) override;
bool HasHitTestMask() const override;
- void GetHitTestMask(gfx::Path* mask) const override;
+ void GetHitTestMask(SkPath* mask) const override;
// Overridden from aura::WindowObserver:
void OnWindowPropertyChanged(aura::Window* window,
diff --git a/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc b/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
index b4de50c7e2b..651cff73ef5 100644
--- a/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
@@ -25,11 +25,11 @@ class TestFocusRules : public wm::BaseFocusRules {
void set_can_activate(bool can_activate) { can_activate_ = can_activate; }
// wm::BaseFocusRules overrides:
- bool SupportsChildActivation(aura::Window* window) const override {
+ bool SupportsChildActivation(const aura::Window* window) const override {
return true;
}
- bool CanActivateWindow(aura::Window* window) const override {
+ bool CanActivateWindow(const aura::Window* window) const override {
return can_activate_;
}
@@ -49,11 +49,6 @@ using NativeWidgetAuraTest = ViewsInteractiveUITestBase;
// not be grabbed. And focus will be given/restored the next time the widget is
// made active. (crbug.com/621791)
TEST_F(NativeWidgetAuraTest, NonActiveWindowRequestImeFocus) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
TestFocusRules* test_focus_rules = new TestFocusRules;
std::unique_ptr<wm::FocusController> focus_controller =
std::make_unique<wm::FocusController>(test_focus_rules);
diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc
index ee5f354c7c0..98510e6221a 100644
--- a/chromium/ui/views/widget/native_widget_aura_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc
@@ -50,11 +50,11 @@ class TestFocusRules : public wm::BaseFocusRules {
void set_can_activate(bool can_activate) { can_activate_ = can_activate; }
// wm::BaseFocusRules overrides:
- bool SupportsChildActivation(aura::Window* window) const override {
+ bool SupportsChildActivation(const aura::Window* window) const override {
return true;
}
- bool CanActivateWindow(aura::Window* window) const override {
+ bool CanActivateWindow(const aura::Window* window) const override {
return can_activate_;
}
diff --git a/chromium/ui/views/widget/native_widget_delegate.h b/chromium/ui/views/widget/native_widget_delegate.h
index 018bc2ce9d3..9dc91d06fde 100644
--- a/chromium/ui/views/widget/native_widget_delegate.h
+++ b/chromium/ui/views/widget/native_widget_delegate.h
@@ -9,8 +9,9 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
+class SkPath;
+
namespace gfx {
-class Path;
class Point;
class Size;
}
@@ -48,6 +49,9 @@ class VIEWS_EXPORT NativeWidgetDelegate {
// Returns true if the window can be activated.
virtual bool CanActivate() const = 0;
+ // Returns true if the native widget has been initialized.
+ virtual bool IsNativeWidgetInitialized() const = 0;
+
// Prevents the window from being rendered as deactivated. This state is
// reset automatically as soon as the window becomes activated again. There is
// no ability to control the state through this API as this leads to sync
@@ -70,9 +74,7 @@ class VIEWS_EXPORT NativeWidgetDelegate {
virtual void OnNativeWidgetVisibilityChanged(bool visible) = 0;
// Called when the native widget is created.
- // The |desktop_widget| bool is true for widgets created in the desktop and
- // false for widgets created in the shell.
- virtual void OnNativeWidgetCreated(bool desktop_widget) = 0;
+ virtual void OnNativeWidgetCreated() = 0;
// Called just before the native widget is destroyed. This is the delegate's
// last chance to do anything with the native widget handle.
@@ -132,7 +134,7 @@ class VIEWS_EXPORT NativeWidgetDelegate {
virtual bool HasHitTestMask() const = 0;
// Provides the hit-test mask if HasHitTestMask above returns true.
- virtual void GetHitTestMask(gfx::Path* mask) const = 0;
+ virtual void GetHitTestMask(SkPath* mask) const = 0;
virtual Widget* AsWidget() = 0;
virtual const Widget* AsWidget() const = 0;
diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h
index 3ba1733df6f..409fe0b03f8 100644
--- a/chromium/ui/views/widget/native_widget_mac.h
+++ b/chromium/ui/views/widget/native_widget_mac.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_
#include "base/macros.h"
+#include "ui/base/window_open_disposition.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/widget/native_widget_private.h"
@@ -19,6 +20,7 @@ namespace views_bridge_mac {
namespace mojom {
class BridgedNativeWidget;
class CreateWindowParams;
+class ValidateUserInterfaceItemResult;
} // namespace mojom
} // namespace views_bridge_mac
@@ -48,9 +50,9 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
// destroyed.
void WindowDestroyed();
- // Returns the vertical position that sheets should be anchored, in pixels
- // from the bottom of the window.
- virtual int SheetPositionY();
+ // The vertical position from which sheets should be anchored, from the top
+ // of the content view.
+ virtual int32_t SheetOffsetY();
// Returns in |override_titlebar_height| whether or not to override the
// titlebar height and in |titlebar_height| the height of the titlebar.
@@ -63,6 +65,21 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
// Handle "Move focus to the window toolbar" shortcut.
virtual void OnFocusWindowToolbar() {}
+ // Allows subclasses to override the behavior for
+ // -[NSUserInterfaceValidations validateUserInterfaceItem].
+ virtual void ValidateUserInterfaceItem(
+ int32_t command,
+ views_bridge_mac::mojom::ValidateUserInterfaceItemResult* result) {}
+
+ // Execute the chrome command |command| with |window_open_disposition|. If
+ // |is_before_first_responder| then only call ExecuteCommand if the command
+ // is reserved and extension shortcut handling is not suspended. Returns in
+ // |was_executed| whether or not ExecuteCommand was called (regardless of what
+ // the return value for ExecuteCommand was).
+ virtual bool ExecuteCommand(int32_t command,
+ WindowOpenDisposition window_open_disposition,
+ bool is_before_first_responder);
+
// internal::NativeWidgetPrivate:
void InitNativeWidget(const Widget::InitParams& params) override;
void OnWidgetInitDone() override;
@@ -133,6 +150,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
ui::DragDropTypes::DragEventSource source) override;
void SchedulePaintInRect(const gfx::Rect& rect) override;
void SetCursor(gfx::NativeCursor cursor) override;
+ void ShowEmojiPanel() override;
bool IsMouseEventsEnabled() const override;
bool IsMouseButtonDown() const override;
void ClearNativeFocus() override;
@@ -149,9 +167,13 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
bool IsTranslucentWindowOpacitySupported() const override;
ui::GestureRecognizer* GetGestureRecognizer() override;
void OnSizeConstraintsChanged() override;
- void RepostNativeEvent(gfx::NativeEvent native_event) override;
std::string GetName() const override;
+ // Calls |callback| with the newly created NativeWidget whenever a
+ // NativeWidget is created.
+ static void SetInitNativeWidgetCallback(
+ const base::RepeatingCallback<void(NativeWidgetMac*)>& callback);
+
protected:
virtual void PopulateCreateWindowParams(
const Widget::InitParams& widget_params,
@@ -171,6 +193,10 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
// windows are to be created in the current process.
virtual BridgeFactoryHost* GetBridgeFactoryHost();
+ // Called after the window has been initialized. Allows subclasses to perform
+ // additional initialization.
+ virtual void OnWindowInitialized() {}
+
// Optional hook for subclasses invoked by WindowDestroying().
virtual void OnWindowDestroying(gfx::NativeWindow window) {}
@@ -181,7 +207,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
internal::NativeWidgetDelegate* delegate() { return delegate_; }
views_bridge_mac::mojom::BridgedNativeWidget* bridge() const;
BridgedNativeWidgetImpl* bridge_impl() const;
- BridgedNativeWidgetHostImpl* bridge_host_for_testing() const {
+ BridgedNativeWidgetHostImpl* bridge_host() const {
return bridge_host_.get();
}
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
index 9f76453e071..d4459e79fec 100644
--- a/chromium/ui/views/widget/native_widget_mac.mm
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -42,6 +42,9 @@ namespace {
base::LazyInstance<ui::GestureRecognizerImplMac>::Leaky
g_gesture_recognizer_instance = LAZY_INSTANCE_INITIALIZER;
+static base::RepeatingCallback<void(NativeWidgetMac*)>*
+ g_init_native_widget_callback = nullptr;
+
NSInteger StyleMaskForParams(const Widget::InitParams& params) {
// If the Widget is modal, it will be displayed as a sheet. This works best if
// it has NSTitledWindowMask. For example, with NSBorderlessWindowMask, the
@@ -96,10 +99,8 @@ void NativeWidgetMac::WindowDestroyed() {
delete this;
}
-int NativeWidgetMac::SheetPositionY() {
- NSView* view = GetNativeView().GetNativeNSView();
- return
- [view convertPoint:NSMakePoint(0, NSHeight([view frame])) toView:nil].y;
+int32_t NativeWidgetMac::SheetOffsetY() {
+ return 0;
}
void NativeWidgetMac::GetWindowFrameTitlebarHeight(
@@ -109,6 +110,15 @@ void NativeWidgetMac::GetWindowFrameTitlebarHeight(
*titlebar_height = 0;
}
+bool NativeWidgetMac::ExecuteCommand(
+ int32_t command,
+ WindowOpenDisposition window_open_disposition,
+ bool is_before_first_responder) {
+ // This is supported only by subclasses in chrome/browser/ui.
+ NOTIMPLEMENTED();
+ return false;
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetMac, internal::NativeWidgetPrivate implementation:
@@ -142,13 +152,14 @@ void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
}
bridge_host_->SetParent(parent_host);
bridge_host_->InitWindow(params);
+ OnWindowInitialized();
// Only set always-on-top here if it is true since setting it may affect how
// the window is treated by Expose.
if (params.keep_on_top)
SetAlwaysOnTop(true);
- delegate_->OnNativeWidgetCreated(true);
+ delegate_->OnNativeWidgetCreated();
DCHECK(GetWidget()->GetRootView());
bridge_host_->SetRootView(GetWidget()->GetRootView());
@@ -160,6 +171,9 @@ void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
}
bridge_host_->CreateCompositor(params);
+
+ if (g_init_native_widget_callback)
+ g_init_native_widget_callback->Run(this);
}
void NativeWidgetMac::OnWidgetInitDone() {
@@ -373,9 +387,9 @@ void NativeWidgetMac::Close() {
}
void NativeWidgetMac::CloseNow() {
- if (bridge())
- bridge()->CloseWindowNow();
- // Note: |bridge_host_| will be deleted her, and |this| will be deleted here
+ if (bridge_host_)
+ bridge_host_->CloseWindowNow();
+ // Note: |bridge_host_| will be deleted here, and |this| will be deleted here
// when ownership_ == NATIVE_WIDGET_OWNS_WIDGET,
}
@@ -536,6 +550,13 @@ void NativeWidgetMac::SetCursor(gfx::NativeCursor cursor) {
bridge_impl()->SetCursor(cursor);
}
+void NativeWidgetMac::ShowEmojiPanel() {
+ // We must plumb the call to ui::ShowEmojiPanel() over the bridge so that it
+ // is called from the correct process.
+ if (bridge())
+ bridge()->ShowEmojiPanel();
+}
+
bool NativeWidgetMac::IsMouseEventsEnabled() const {
// On platforms with touch, mouse events get disabled and calls to this method
// can affect hover states. Since there is no touch on desktop Mac, this is
@@ -626,14 +647,25 @@ void NativeWidgetMac::OnSizeConstraintsChanged() {
widget->widget_delegate()->CanMaximize());
}
-void NativeWidgetMac::RepostNativeEvent(gfx::NativeEvent native_event) {
- NOTIMPLEMENTED();
-}
-
std::string NativeWidgetMac::GetName() const {
return name_;
}
+// static
+void NativeWidgetMac::SetInitNativeWidgetCallback(
+ const base::RepeatingCallback<void(NativeWidgetMac*)>& callback) {
+ DCHECK(!g_init_native_widget_callback || callback.is_null());
+ if (callback.is_null()) {
+ if (g_init_native_widget_callback) {
+ delete g_init_native_widget_callback;
+ g_init_native_widget_callback = nullptr;
+ }
+ return;
+ }
+ g_init_native_widget_callback =
+ new base::RepeatingCallback<void(NativeWidgetMac*)>(callback);
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetMac, protected:
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 1bb90b81c39..d7688f03dee 100644
--- a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
@@ -15,7 +15,6 @@
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/test_widget_observer.h"
-#include "ui/views/test/views_interactive_ui_test_base.h"
#include "ui/views/test/widget_test.h"
namespace views {
@@ -33,7 +32,7 @@ class NativeWidgetMacInteractiveUITest
// WidgetTest:
void SetUp() override {
- ViewsInteractiveUITestBase::InteractiveSetUp();
+ SetUpForInteractiveTests();
WidgetTest::SetUp();
}
@@ -294,7 +293,7 @@ TEST_F(NativeWidgetMacInteractiveUITest, BubbleDismiss) {
// away from any Widget when the window is torn down. This test ensures that
// global references AppKit may have held on to are also updated.
TEST_F(NativeWidgetMacInteractiveUITest, GlobalNSTextInputContextUpdates) {
- Widget* widget = CreateNativeDesktopWidget();
+ Widget* widget = CreateTopLevelNativeWidget();
Textfield* textfield = new Textfield;
textfield->SetBounds(0, 0, 100, 100);
widget->GetContentsView()->AddChildView(textfield);
diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm
index 74b583c02bc..85370ab0432 100644
--- a/chromium/ui/views/widget/native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm
@@ -599,10 +599,12 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
EXPECT_EQ(3, view->paint_count());
widget->CloseNow();
+}
+TEST_F(NativeWidgetMacTest, MiniaturizeFramelessWindow) {
// Create a widget without a minimize button.
- widget = CreateTopLevelFramelessPlatformWidget();
- ns_window = widget->GetNativeWindow().GetNativeNSWindow();
+ Widget* widget = CreateTopLevelFramelessPlatformWidget();
+ NSWindow* ns_window = widget->GetNativeWindow().GetNativeNSWindow();
widget->SetBounds(gfx::Rect(100, 100, 300, 300));
widget->Show();
EXPECT_FALSE(widget->IsMinimized());
@@ -613,6 +615,8 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
// But this should work.
widget->Minimize();
+ base::RunLoop().RunUntilIdle();
+
EXPECT_TRUE(widget->IsMinimized());
// Test closing while minimized.
@@ -697,6 +701,11 @@ TEST_F(NativeWidgetMacTest, SetCursor) {
widget->CloseNow();
}
+// This test uses the deprecated NSObject accessibility API - see
+// https://crbug.com/921109.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
// Tests that an accessibility request from the system makes its way through to
// a views::Label filling the window.
TEST_F(NativeWidgetMacTest, AccessibilityIntegration) {
@@ -722,6 +731,8 @@ TEST_F(NativeWidgetMacTest, AccessibilityIntegration) {
widget->CloseNow();
}
+#pragma clang diagnostic pop
+
namespace {
Widget* AttachPopupToNativeParent(NSWindow* native_parent) {
@@ -1562,7 +1573,7 @@ TEST_F(NativeWidgetMacTest, NoopReparentNativeView) {
[parent close];
- Widget* parent_widget = CreateNativeDesktopWidget();
+ Widget* parent_widget = CreateTopLevelNativeWidget();
parent = parent_widget->GetNativeWindow().GetNativeNSWindow();
dialog = views::DialogDelegate::CreateDialogWidget(
new DialogDelegateView, nullptr, [parent contentView]);
@@ -1680,7 +1691,7 @@ TEST_F(NativeWidgetMacTest, NoParentDelegateDuringTeardown) {
// Tests Cocoa properties that should be given to particular widget types.
TEST_F(NativeWidgetMacTest, NativeProperties) {
// Create a regular widget (TYPE_WINDOW).
- Widget* regular_widget = CreateNativeDesktopWidget();
+ Widget* regular_widget = CreateTopLevelNativeWidget();
EXPECT_TRUE([regular_widget->GetNativeWindow().GetNativeNSWindow()
canBecomeKeyWindow]);
EXPECT_TRUE([regular_widget->GetNativeWindow().GetNativeNSWindow()
@@ -2405,6 +2416,33 @@ TEST_F(NativeWidgetMacTest, TouchBar) {
delegate->GetWidget()->CloseNow();
}
+TEST_F(NativeWidgetMacTest, InitCallback) {
+ NativeWidget* observed_native_widget = nullptr;
+ const auto callback = base::BindRepeating(
+ [](NativeWidget** observed, NativeWidgetMac* native_widget) {
+ *observed = native_widget;
+ },
+ &observed_native_widget);
+ NativeWidgetMac::SetInitNativeWidgetCallback(callback);
+
+ Widget* widget_a = CreateTopLevelPlatformWidget();
+ EXPECT_EQ(observed_native_widget, widget_a->native_widget());
+ Widget* widget_b = CreateTopLevelPlatformWidget();
+ EXPECT_EQ(observed_native_widget, widget_b->native_widget());
+
+ auto empty = base::RepeatingCallback<void(NativeWidgetMac*)>();
+ DCHECK(empty.is_null());
+ NativeWidgetMac::SetInitNativeWidgetCallback(empty);
+ observed_native_widget = nullptr;
+ Widget* widget_c = CreateTopLevelPlatformWidget();
+ // The original callback from above should no longer be firing.
+ EXPECT_EQ(observed_native_widget, nullptr);
+
+ widget_a->CloseNow();
+ widget_b->CloseNow();
+ widget_c->CloseNow();
+}
+
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_private.cc b/chromium/ui/views/widget/native_widget_private.cc
index e8ad491578d..a5933a86da9 100644
--- a/chromium/ui/views/widget/native_widget_private.cc
+++ b/chromium/ui/views/widget/native_widget_private.cc
@@ -4,6 +4,7 @@
#include "ui/views/widget/native_widget_private.h"
+#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
@@ -21,5 +22,9 @@ gfx::Rect NativeWidgetPrivate::ConstrainBoundsToDisplayWorkArea(
return new_bounds;
}
+void NativeWidgetPrivate::ShowEmojiPanel() {
+ ui::ShowEmojiPanel();
+}
+
} // namespace internal
} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_private.h b/chromium/ui/views/widget/native_widget_private.h
index 6aedb90e714..e4af6f16173 100644
--- a/chromium/ui/views/widget/native_widget_private.h
+++ b/chromium/ui/views/widget/native_widget_private.h
@@ -212,6 +212,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
ui::DragDropTypes::DragEventSource source) = 0;
virtual void SchedulePaintInRect(const gfx::Rect& rect) = 0;
virtual void SetCursor(gfx::NativeCursor cursor) = 0;
+ virtual void ShowEmojiPanel();
virtual bool IsMouseEventsEnabled() const = 0;
// Returns true if any mouse button is currently down.
virtual bool IsMouseButtonDown() const = 0;
@@ -231,9 +232,6 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual ui::GestureRecognizer* GetGestureRecognizer() = 0;
virtual void OnSizeConstraintsChanged() = 0;
- // Repost an unhandled event to the native widget for default OS processing.
- virtual void RepostNativeEvent(gfx::NativeEvent native_event) = 0;
-
// Returns an internal name that matches the name of the associated Widget.
virtual std::string GetName() const = 0;
diff --git a/chromium/ui/views/widget/native_widget_unittest.cc b/chromium/ui/views/widget/native_widget_unittest.cc
index 661ea6a9611..d7aa5baf0d1 100644
--- a/chromium/ui/views/widget/native_widget_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_unittest.cc
@@ -82,10 +82,6 @@ TEST_F(NativeWidgetTest, GetTopLevelNativeWidget1) {
// |toplevel_widget| has the toplevel NativeWidget.
TEST_F(NativeWidgetTest, GetTopLevelNativeWidget2) {
- // This test relies on GetContext(). http://crbug.com/663809.
- if (IsMus())
- return;
-
internal::NativeWidgetPrivate* child_widget = CreateNativeSubWidget();
{
ScopedTestWidget toplevel_widget(CreateNativeWidget());
diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc
index 67a7e3fb70a..674fa02685b 100644
--- a/chromium/ui/views/widget/root_view.cc
+++ b/chromium/ui/views/widget/root_view.cc
@@ -221,6 +221,15 @@ void RootView::ThemeChanged() {
View::PropagateThemeChanged();
}
+void RootView::ResetEventHandlers() {
+ explicit_mouse_handler_ = false;
+ mouse_pressed_handler_ = nullptr;
+ mouse_move_handler_ = nullptr;
+ gesture_handler_ = nullptr;
+ event_dispatch_target_ = nullptr;
+ old_dispatch_target_ = nullptr;
+}
+
void RootView::DeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) {
View::PropagateDeviceScaleFactorChanged(old_device_scale_factor,
@@ -633,12 +642,7 @@ void RootView::VisibilityChanged(View* /*starting_from*/, bool is_visible) {
// When the root view is being hidden (e.g. when widget is minimized)
// handlers are reset, so that after it is reshown, events are not captured
// by old handlers.
- explicit_mouse_handler_ = false;
- mouse_pressed_handler_ = NULL;
- mouse_move_handler_ = NULL;
- gesture_handler_ = NULL;
- event_dispatch_target_ = NULL;
- old_dispatch_target_ = NULL;
+ ResetEventHandlers();
}
}
diff --git a/chromium/ui/views/widget/root_view.h b/chromium/ui/views/widget/root_view.h
index 73c20245f5b..bbf45afb113 100644
--- a/chromium/ui/views/widget/root_view.h
+++ b/chromium/ui/views/widget/root_view.h
@@ -83,6 +83,10 @@ class VIEWS_EXPORT RootView : public View,
// hierarchy.
void ThemeChanged();
+ // Used to clear event handlers so events aren't captured by old event
+ // handlers, e.g., when the widget is minimized.
+ void ResetEventHandlers();
+
// Public API for broadcasting device scale factor change notifications to
// this View hierarchy.
void DeviceScaleFactorChanged(float old_device_scale_factor,
diff --git a/chromium/ui/views/widget/root_view_unittest.cc b/chromium/ui/views/widget/root_view_unittest.cc
index d1bee1793e7..fadfa68b14b 100644
--- a/chromium/ui/views/widget/root_view_unittest.cc
+++ b/chromium/ui/views/widget/root_view_unittest.cc
@@ -19,7 +19,7 @@
namespace views {
namespace test {
-typedef ViewsTestBase RootViewTest;
+using RootViewTest = ViewsTestBase;
class DeleteOnKeyEventView : public View {
public:
@@ -582,11 +582,15 @@ TEST_F(RootViewTest, SingleLayoutDuringInit) {
DialogDelegate::CreateDialogWidget(delegate, GetContext(), nullptr);
EXPECT_EQ(1, delegate->layout_count());
widget->CloseNow();
+}
+
+using RootViewDesktopNativeWidgetTest = ViewsTestWithDesktopNativeWidget;
- // Also test Aura desktop Widget codepaths.
- test_views_delegate()->set_use_desktop_native_widgets(true);
- delegate = new RootViewTestDialogDelegate();
- widget = DialogDelegate::CreateDialogWidget(delegate, GetContext(), nullptr);
+// Also test Aura desktop Widget codepaths.
+TEST_F(RootViewDesktopNativeWidgetTest, SingleLayoutDuringInit) {
+ RootViewTestDialogDelegate* delegate = new RootViewTestDialogDelegate();
+ Widget* widget =
+ DialogDelegate::CreateDialogWidget(delegate, GetContext(), nullptr);
EXPECT_EQ(1, delegate->layout_count());
widget->CloseNow();
}
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index 0353201e793..496e7240e2c 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -4,6 +4,8 @@
#include "ui/views/widget/widget.h"
+#include <utility>
+
#include "base/auto_reset.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -41,7 +43,6 @@
#if defined(USE_AURA)
#include "ui/aura/env.h" // nogncheck
-#include "ui/aura/window.h" // nogncheck
#endif
namespace views {
@@ -169,7 +170,6 @@ Widget::Widget()
is_secondary_widget_(true),
frame_type_(FRAME_TYPE_DEFAULT),
always_render_as_active_(false),
- widget_closed_(false),
saved_show_state_(ui::SHOW_STATE_DEFAULT),
focus_on_creation_(true),
is_top_level_(false),
@@ -296,7 +296,6 @@ gfx::Size Widget::GetLocalizedContentsSize(int col_resource_id,
// static
bool Widget::RequiresNonClientView(InitParams::Type type) {
return type == InitParams::TYPE_WINDOW ||
- type == InitParams::TYPE_PANEL ||
type == InitParams::TYPE_BUBBLE;
}
@@ -314,9 +313,9 @@ void Widget::Init(const InitParams& in_params) {
is_top_level_ = !params.child;
if (params.opacity == views::Widget::InitParams::INFER_OPACITY &&
- params.type != views::Widget::InitParams::TYPE_WINDOW &&
- params.type != views::Widget::InitParams::TYPE_PANEL)
+ params.type != views::Widget::InitParams::TYPE_WINDOW) {
params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
+ }
if (ViewsDelegate::GetInstance())
ViewsDelegate::GetInstance()->OnBeforeWidgetInit(&params, this);
@@ -385,6 +384,10 @@ void Widget::Init(const InitParams& in_params) {
native_widget_->OnWidgetInitDone();
}
+void Widget::ShowEmojiPanel() {
+ native_widget_->ShowEmojiPanel();
+}
+
// Unconverted methods (see header) --------------------------------------------
gfx::NativeView Widget::GetNativeView() const {
@@ -569,7 +572,7 @@ void Widget::SetShape(std::unique_ptr<ShapeRects> shape) {
native_widget_->SetShape(std::move(shape));
}
-void Widget::Close() {
+void Widget::CloseWithReason(ClosedReason closed_reason) {
if (widget_closed_) {
// It appears we can hit this code path if you close a modal dialog then
// close the last browser before the destructor is hit, which triggers
@@ -580,9 +583,14 @@ void Widget::Close() {
if (non_client_view_ && !non_client_view_->CanClose())
return;
+ // This is the last chance to cancel closing.
+ if (widget_delegate_ && !widget_delegate_->OnCloseRequested(closed_reason))
+ return;
+
// The actions below can cause this function to be called again, so mark
// |this| as closed early. See crbug.com/714334
widget_closed_ = true;
+ closed_reason_ = closed_reason;
SaveWindowPlacement();
// During tear-down the top-level focus manager becomes unavailable to
@@ -599,6 +607,10 @@ void Widget::Close() {
native_widget_->Close();
}
+void Widget::Close() {
+ CloseWithReason(ClosedReason::kUnspecified);
+}
+
void Widget::CloseNow() {
for (WidgetObserver& observer : observers_)
observer.OnWidgetClosing(this);
@@ -1038,6 +1050,10 @@ bool Widget::IsAlwaysRenderAsActive() const {
return always_render_as_active_;
}
+bool Widget::IsNativeWidgetInitialized() const {
+ return native_widget_initialized_;
+}
+
bool Widget::OnNativeWidgetActivationChanged(bool active) {
if (g_disable_activation_change_handling_)
return false;
@@ -1082,9 +1098,9 @@ void Widget::OnNativeWidgetVisibilityChanged(bool visible) {
root->layer()->SetVisible(visible);
}
-void Widget::OnNativeWidgetCreated(bool desktop_widget) {
+void Widget::OnNativeWidgetCreated() {
if (is_top_level())
- focus_manager_ = FocusManagerFactory::Create(this, desktop_widget);
+ focus_manager_ = FocusManagerFactory::Create(this);
native_widget_->InitModalType(widget_delegate_->GetModalType());
@@ -1313,7 +1329,7 @@ bool Widget::HasHitTestMask() const {
return widget_delegate_->WidgetHasHitTestMask();
}
-void Widget::GetHitTestMask(gfx::Path* mask) const {
+void Widget::GetHitTestMask(SkPath* mask) const {
DCHECK(mask);
widget_delegate_->GetWidgetHitTestMask(mask);
}
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index e7116c1b21d..0323bbb17b1 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -134,12 +134,27 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
ANIMATE_NONE = 0x4,
};
+ // Represents the reason a Widget was closed, if it is known.
+ //
+ // For backwards compatibility, we default to kUnspecified when
+ // Widget::Close() is called. Note that we do not currently handle close
+ // reason for menu or for the main Chrome browser, as we have no reason to
+ // specifically differentiate those yet.
+ //
+ // Add additional values as needed.
+ enum class ClosedReason {
+ kUnspecified = 0, // No reason was given for the widget closing.
+ kEscKeyPressed, // The ESC key was pressed to cancel the widget.
+ kCloseButtonClicked, // The [X] button was explicitly clicked.
+ kLostFocus, // The widget destroyed itself when it lost focus.
+ kCancelButtonClicked, // The widget's cancel button was clicked.
+ kAcceptButtonClicked // The widget's done/accept button was clicked.
+ };
+
struct VIEWS_EXPORT InitParams {
enum Type {
TYPE_WINDOW, // A decorated Window, like a frame window.
// Widgets of TYPE_WINDOW will have a NonClientView.
- TYPE_PANEL, // Always on top window managed by PanelManager.
- // Widgets of TYPE_PANEL will have a NonClientView.
TYPE_WINDOW_FRAMELESS,
// An undecorated Window.
TYPE_CONTROL, // A control, like a button.
@@ -468,8 +483,15 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// be rectangular.
void SetShape(std::unique_ptr<ShapeRects> shape);
- // Hides the widget then closes it after a return to the message loop.
- virtual void Close();
+ // Equivalent to CloseWithReason(ClosedReason::kUnspecified).
+ // DEPRECATED: Please use CloseWithReason() instead.
+ void Close();
+
+ // Hides the widget, then closes it after a return to the message loop,
+ // specifying the reason for it having been closed.
+ // Note that while you can pass ClosedReason::kUnspecified, it is highly
+ // discouraged and only supported for backwards-compatibility with Close().
+ void CloseWithReason(ClosedReason closed_reason);
// TODO(beng): Move off public API.
// Closes the widget immediately. Compare to |Close|. This will destroy the
@@ -481,6 +503,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// set to true after Close() has been invoked on the NativeWidget.
bool IsClosed() const;
+ // Returns the reason the widget was closed, if it was specified.
+ ClosedReason closed_reason() const { return closed_reason_; }
+
// Shows the widget. The widget is activated if during initialization the
// can_activate flag in the InitParams structure is set to true.
void Show();
@@ -622,6 +647,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Tell the window to update its icon from the delegate.
void UpdateWindowIcon();
+ // Shows the platform specific emoji picker for this widget.
+ void ShowEmojiPanel();
+
// Retrieves the focus traversable for this widget.
FocusTraversable* GetFocusTraversable();
@@ -780,6 +808,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
bool IsModal() const override;
bool IsDialogBox() const override;
bool CanActivate() const override;
+ bool IsNativeWidgetInitialized() const override;
bool IsAlwaysRenderAsActive() const override;
void SetAlwaysRenderAsActive(bool always_render_as_active) override;
bool OnNativeWidgetActivationChanged(bool active) override;
@@ -787,7 +816,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
void OnNativeBlur() override;
void OnNativeWidgetVisibilityChanging(bool visible) override;
void OnNativeWidgetVisibilityChanged(bool visible) override;
- void OnNativeWidgetCreated(bool desktop_widget) override;
+ void OnNativeWidgetCreated() override;
void OnNativeWidgetDestroying() override;
void OnNativeWidgetDestroyed() override;
gfx::Size GetMinimumSize() const override;
@@ -808,7 +837,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
void OnGestureEvent(ui::GestureEvent* event) override;
bool ExecuteCommand(int command_id) override;
bool HasHitTestMask() const override;
- void GetHitTestMask(gfx::Path* mask) const override;
+ void GetHitTestMask(SkPath* mask) const override;
Widget* AsWidget() override;
const Widget* AsWidget() const override;
bool SetInitialFocus(ui::WindowShowState show_state) override;
@@ -928,7 +957,12 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
bool always_render_as_active_;
// Set to true if the widget is in the process of closing.
- bool widget_closed_;
+ bool widget_closed_ = false;
+
+ // The reason the widget was closed.
+ // Note that this may be ClosedReason::kUnspecified if the deprecated Close()
+ // method was called rather than CloseWithReason().
+ ClosedReason closed_reason_ = ClosedReason::kUnspecified;
// The saved "show" state for this window. See note in SetInitialBounds
// that explains why we save this.
diff --git a/chromium/ui/views/widget/widget_aura_utils.cc b/chromium/ui/views/widget/widget_aura_utils.cc
index 348f828ff8f..85cedf9f62b 100644
--- a/chromium/ui/views/widget/widget_aura_utils.cc
+++ b/chromium/ui/views/widget/widget_aura_utils.cc
@@ -13,8 +13,6 @@ aura::client::WindowType GetAuraWindowTypeForWidgetType(
switch (type) {
case Widget::InitParams::TYPE_WINDOW:
return aura::client::WINDOW_TYPE_NORMAL;
- case Widget::InitParams::TYPE_PANEL:
- return aura::client::WINDOW_TYPE_PANEL;
case Widget::InitParams::TYPE_CONTROL:
return aura::client::WINDOW_TYPE_CONTROL;
case Widget::InitParams::TYPE_WINDOW_FRAMELESS:
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
index f87e90d76e4..fb1eb96f85b 100644
--- a/chromium/ui/views/widget/widget_delegate.cc
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -32,6 +32,10 @@ void WidgetDelegate::OnDisplayChanged() {
void WidgetDelegate::OnWorkAreaChanged() {
}
+bool WidgetDelegate::OnCloseRequested(Widget::ClosedReason close_reason) {
+ return true;
+}
+
View* WidgetDelegate::GetInitiallyFocusedView() {
return nullptr;
}
@@ -169,7 +173,7 @@ bool WidgetDelegate::WidgetHasHitTestMask() const {
return false;
}
-void WidgetDelegate::GetWidgetHitTestMask(gfx::Path* mask) const {
+void WidgetDelegate::GetWidgetHitTestMask(SkPath* mask) const {
DCHECK(mask);
}
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
index 5e394416c1e..186a5509c13 100644
--- a/chromium/ui/views/widget/widget_delegate.h
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -12,6 +12,7 @@
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
namespace gfx {
class ImageSkia;
@@ -24,7 +25,6 @@ class ClientView;
class DialogDelegate;
class NonClientFrameView;
class View;
-class Widget;
// Handles events on Widgets in context-specific ways.
class VIEWS_EXPORT WidgetDelegate {
@@ -46,6 +46,15 @@ class VIEWS_EXPORT WidgetDelegate {
// menu bars, etc.) changes in size.
virtual void OnWorkAreaChanged();
+ // Called when the window has been requested to close, after all other checks
+ // have run. Returns whether the window should be allowed to close (default is
+ // true).
+ //
+ // Can be used as an alternative to specifying a custom ClientView with
+ // the CanClose() method, or in widget types which do not support a
+ // ClientView.
+ virtual bool OnCloseRequested(Widget::ClosedReason close_reason);
+
// Returns the view that should have the focus when the widget is shown. If
// NULL no view is focused.
virtual View* GetInitiallyFocusedView();
@@ -166,7 +175,7 @@ class VIEWS_EXPORT WidgetDelegate {
virtual bool WidgetHasHitTestMask() const;
// Provides the hit-test mask if HasHitTestMask above returns true.
- virtual void GetWidgetHitTestMask(gfx::Path* mask) const;
+ virtual void GetWidgetHitTestMask(SkPath* mask) const;
// Returns true if focus should advance to the top level widget when
// tab/shift-tab is hit and on the last/first focusable view. Default returns
diff --git a/chromium/ui/views/widget/widget_hwnd_utils.cc b/chromium/ui/views/widget/widget_hwnd_utils.cc
index c7296fed234..5bcb8d8b9ba 100644
--- a/chromium/ui/views/widget/widget_hwnd_utils.cc
+++ b/chromium/ui/views/widget/widget_hwnd_utils.cc
@@ -54,13 +54,6 @@ void CalculateWindowStylesFromInitParams(
// Set type-dependent style attributes.
switch (params.type) {
- case Widget::InitParams::TYPE_PANEL:
- *ex_style |= WS_EX_TOPMOST;
- if (params.remove_standard_frame) {
- *style |= WS_POPUP;
- break;
- }
- FALLTHROUGH;
case Widget::InitParams::TYPE_WINDOW: {
// WS_OVERLAPPEDWINDOW is equivalent to:
// WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
@@ -128,6 +121,12 @@ bool DidClientAreaSizeChange(const WINDOWPOS* window_pos) {
window_pos->flags & SWP_FRAMECHANGED;
}
+bool DidMinimizedChange(UINT old_size_param, UINT new_size_param) {
+ return (
+ (old_size_param == SIZE_MINIMIZED && new_size_param != SIZE_MINIMIZED) ||
+ (old_size_param != SIZE_MINIMIZED && new_size_param == SIZE_MINIMIZED));
+}
+
void ConfigureWindowStyles(
HWNDMessageHandler* handler,
const Widget::InitParams& params,
diff --git a/chromium/ui/views/widget/widget_hwnd_utils.h b/chromium/ui/views/widget/widget_hwnd_utils.h
index 09ee0abe138..a3a28783994 100644
--- a/chromium/ui/views/widget/widget_hwnd_utils.h
+++ b/chromium/ui/views/widget/widget_hwnd_utils.h
@@ -24,6 +24,10 @@ class NativeWidgetDelegate;
// resized or its frame changing.
bool DidClientAreaSizeChange(const WINDOWPOS* window_pos);
+// Returns true if the size data provided indicates that the window
+// transitioned from a minimized state to something else or vice versa.
+bool DidMinimizedChange(UINT old_size_param, UINT new_size_param);
+
// Sets styles appropriate for |params| on |handler|.
void ConfigureWindowStyles(
HWNDMessageHandler* handler,
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index 22d9afaae78..3363537a980 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -8,7 +8,6 @@
#include "base/command_line.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
@@ -16,18 +15,16 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/windows_version.h"
#include "build/build_config.h"
-#include "mojo/core/embedder/embedder.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/test/ui_controls.h"
-#include "ui/base/ui_base_paths.h"
+#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gl/test/gl_surface_test_support.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_test_api.h"
#include "ui/views/focus/focus_manager.h"
@@ -36,6 +33,7 @@
#include "ui/views/test/views_interactive_ui_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/touchui/touch_selection_controller_impl.h"
+#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_utils.h"
#include "ui/views/window/dialog_delegate.h"
@@ -272,24 +270,11 @@ class PropertyWaiter {
class WidgetTestInteractive : public WidgetTest {
public:
- WidgetTestInteractive() {}
- ~WidgetTestInteractive() override {}
+ WidgetTestInteractive() = default;
+ ~WidgetTestInteractive() override = default;
void SetUp() override {
- // On mus these tests run as part of views::ViewsTestSuite which already
- // does this initialization.
- if (!IsMus()) {
- // Mojo is initialized here similar to how each browser test case
- // initializes Mojo when starting. This only works because each
- // interactive_ui_test runs in a new process.
- mojo::core::Init();
-
- gl::GLSurfaceTestSupport::InitializeOneOff();
- ui::RegisterPathProvider();
- base::FilePath ui_test_pak_path;
- ASSERT_TRUE(base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
- ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
- }
+ SetUpForInteractiveTests();
WidgetTest::SetUp();
}
@@ -304,12 +289,27 @@ class WidgetTestInteractive : public WidgetTest {
}
}
#endif // defined (USE_AURA)
+};
+
+class DesktopWidgetTestInteractive : public WidgetTestInteractive {
+ public:
+ DesktopWidgetTestInteractive() = default;
+ ~DesktopWidgetTestInteractive() override = default;
+ // WidgetTestInteractive:
+ void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+ WidgetTestInteractive::SetUp();
+ }
+
+ protected:
Widget* CreateWidget() {
- Widget* widget = CreateNativeDesktopWidget();
+ Widget* widget = CreateTopLevelNativeWidget();
widget->SetBounds(gfx::Rect(0, 0, 200, 200));
return widget;
}
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopWidgetTestInteractive);
};
#if defined(OS_WIN)
@@ -322,7 +322,8 @@ class WidgetTestInteractive : public WidgetTest {
// 3. On focusing the native platform window for widget 1, the active aura
// window for widget 1 should be set and that for widget 2 should reset.
// TODO(ananta): Discuss with erg on how to write this test for linux x11 aura.
-TEST_F(WidgetTestInteractive, DesktopNativeWidgetAuraActivationAndFocusTest) {
+TEST_F(DesktopWidgetTestInteractive,
+ DesktopNativeWidgetAuraActivationAndFocusTest) {
// Create widget 1 and expect the active window to be its window.
View* focusable_view1 = new View;
focusable_view1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -411,7 +412,7 @@ class TouchEventHandler : public ui::EventHandler {
};
// TODO(dtapuska): Disabled due to it being flaky crbug.com/817531
-TEST_F(WidgetTestInteractive, DISABLED_TouchNoActivateWindow) {
+TEST_F(DesktopWidgetTestInteractive, DISABLED_TouchNoActivateWindow) {
// ui_controls::SendTouchEvents which uses InjectTouchInput API only works
// on Windows 8 and up.
if (base::win::GetVersion() <= base::win::VERSION_WIN7)
@@ -622,10 +623,6 @@ TEST_F(WidgetTestInteractive, DISABLED_GrabUngrab) {
// Tests mouse move outside of the window into the "resize controller" and back
// will still generate an OnMouseEntered and OnMouseExited event..
TEST_F(WidgetTestInteractive, CheckResizeControllerEvents) {
- // TODO(http://crbug.com/864787): Crashes flakily in mus with ws2.
- if (IsMus())
- return;
-
Widget* toplevel = CreateTopLevelPlatformWidget();
toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
@@ -742,15 +739,12 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) {
// NOTE: for aura-mus-client stacking of top-levels is not maintained in the
// client, so z-order of top-levels can't be determined.
- const bool check_toplevel_z_order = !IsMus();
- if (check_toplevel_z_order)
- EXPECT_TRUE(IsWindowStackedAbove(popover.get(), child));
+ EXPECT_TRUE(IsWindowStackedAbove(popover.get(), child));
EXPECT_TRUE(IsWindowStackedAbove(child, parent.get()));
// Showing the parent again should raise it and its child above the popover.
ShowSync(parent.get());
EXPECT_TRUE(IsWindowStackedAbove(child, parent.get()));
- if (check_toplevel_z_order)
EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get()));
// Test grandchildren.
@@ -759,17 +753,14 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) {
grandchild->ShowInactive();
EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
EXPECT_TRUE(IsWindowStackedAbove(child, parent.get()));
- if (check_toplevel_z_order)
EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get()));
ShowSync(popover.get());
- if (check_toplevel_z_order)
EXPECT_TRUE(IsWindowStackedAbove(popover.get(), grandchild));
EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
ShowSync(parent.get());
EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
- if (check_toplevel_z_order)
EXPECT_TRUE(IsWindowStackedAbove(child, popover.get()));
// Test hiding and reshowing.
@@ -779,7 +770,6 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) {
EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
EXPECT_TRUE(IsWindowStackedAbove(child, parent.get()));
- if (check_toplevel_z_order)
EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get()));
grandchild->Hide();
@@ -788,7 +778,6 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) {
EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
EXPECT_TRUE(IsWindowStackedAbove(child, parent.get()));
- if (check_toplevel_z_order)
EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get()));
}
@@ -1026,7 +1015,7 @@ class ModalDialogDelegate : public DialogDelegateView {
// Tests whether the focused window is set correctly when a modal window is
// created and destroyed. When it is destroyed it should focus the owner window.
-TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
+TEST_F(DesktopWidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
TestWidgetFocusChangeListener focus_listener;
WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener);
const std::vector<gfx::NativeView>& focus_changes =
@@ -1040,8 +1029,6 @@ TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
gfx::Rect initial_bounds(0, 0, 500, 500);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- init_params, &top_level_widget, nullptr);
top_level_widget.Init(init_params);
ShowSync(&top_level_widget);
@@ -1097,7 +1084,7 @@ TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
#endif
// Test that when opening a system-modal window, capture is released.
-TEST_F(WidgetTestInteractive, MAYBE_SystemModalWindowReleasesCapture) {
+TEST_F(DesktopWidgetTestInteractive, MAYBE_SystemModalWindowReleasesCapture) {
TestWidgetFocusChangeListener focus_listener;
WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener);
@@ -1109,8 +1096,6 @@ TEST_F(WidgetTestInteractive, MAYBE_SystemModalWindowReleasesCapture) {
gfx::Rect initial_bounds(0, 0, 500, 500);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- init_params, &top_level_widget, nullptr);
top_level_widget.Init(init_params);
ShowSync(&top_level_widget);
@@ -1140,15 +1125,13 @@ TEST_F(WidgetTestInteractive, MAYBE_SystemModalWindowReleasesCapture) {
#endif // !defined(OS_CHROMEOS)
-TEST_F(WidgetTestInteractive, CanActivateFlagIsHonored) {
+TEST_F(DesktopWidgetTestInteractive, CanActivateFlagIsHonored) {
Widget widget;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.bounds = gfx::Rect(0, 0, 200, 200);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
init_params.activatable = Widget::InitParams::ACTIVATABLE_NO;
- init_params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(init_params, &widget, nullptr);
widget.Init(init_params);
widget.Show();
@@ -1156,12 +1139,19 @@ TEST_F(WidgetTestInteractive, CanActivateFlagIsHonored) {
}
#if defined(USE_AURA)
-// Test that touch selection quick menu is not activated when opened.
-TEST_F(WidgetTestInteractive, TouchSelectionQuickMenuIsNotActivated) {
-#if defined(OS_WIN)
- test_views_delegate()->set_use_desktop_native_widgets(true);
-#endif // !defined(OS_WIN)
+#if defined(OS_CHROMEOS)
+// TODO(crbug.com/916272): investigate fixing and enabling on Chrome OS.
+#define MAYBE_TouchSelectionQuickMenuIsNotActivated \
+ DISABLED_TouchSelectionQuickMenuIsNotActivated
+#else
+#define MAYBE_TouchSelectionQuickMenuIsNotActivated \
+ TouchSelectionQuickMenuIsNotActivated
+#endif
+
+// Test that touch selection quick menu is not activated when opened.
+TEST_F(DesktopWidgetTestInteractive,
+ MAYBE_TouchSelectionQuickMenuIsNotActivated) {
Widget* widget = CreateWidget();
Textfield* textfield = new Textfield;
@@ -1189,9 +1179,10 @@ TEST_F(WidgetTestInteractive, TouchSelectionQuickMenuIsNotActivated) {
}
#endif // defined(USE_AURA)
-TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) {
#if defined(OS_WIN)
- test_views_delegate()->set_use_desktop_native_widgets(true);
+TEST_F(DesktopWidgetTestInteractive, DisableViewDoesNotActivateWidget) {
+#else
+TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) {
#endif // !defined(OS_WIN)
// Create first widget and view, activate the widget, and focus the view.
@@ -1316,8 +1307,6 @@ TEST_F(WidgetTestInteractive, InactiveWidgetDoesNotGrabActivation) {
Widget widget2;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, &widget2, nullptr);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget2.Init(params);
widget2.Show();
@@ -1379,11 +1368,6 @@ TEST_F(WidgetTestInteractive, MAYBE_ExitFullscreenRestoreState) {
// Testing initial focus is assigned properly for normal top-level widgets,
// and subclasses that specify a initially focused child view.
TEST_F(WidgetTestInteractive, InitialFocus) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
// By default, there is no initially focused view (even if there is a
// focusable subview).
Widget* toplevel(CreateTopLevelPlatformWidget());
@@ -1407,7 +1391,7 @@ TEST_F(WidgetTestInteractive, InitialFocus) {
EXPECT_EQ(delegate.view(), widget->GetFocusManager()->GetStoredFocusView());
}
-TEST_F(WidgetTestInteractive, RestoreAfterMinimize) {
+TEST_F(DesktopWidgetTestInteractive, RestoreAfterMinimize) {
Widget* widget = CreateWidget();
ShowSync(widget);
ASSERT_FALSE(widget->IsMinimized());
@@ -1425,11 +1409,69 @@ TEST_F(WidgetTestInteractive, RestoreAfterMinimize) {
widget->CloseNow();
}
+#if defined(OS_WIN)
+// Tests that widget visibility toggles correctly when minimized and maximized
+// on Windows. Test using both the widget API as well as native win32 functions
+// that operate directly on the underlying HWND. Behavior should be the same.
+TEST_F(DesktopWidgetTestInteractive, RestoreAndMinimizeVisibility) {
+ Widget* widget = CreateWidget();
+ ShowSync(widget);
+ ASSERT_FALSE(widget->IsMinimized());
+
+ PropertyWaiter minimize_widget_waiter(
+ base::Bind(&Widget::IsMinimized, base::Unretained(widget)), true);
+ widget->Minimize();
+ EXPECT_TRUE(minimize_widget_waiter.Wait());
+ EXPECT_FALSE(widget->IsVisible());
+
+ PropertyWaiter restore_widget_waiter(
+ base::Bind(&Widget::IsMinimized, base::Unretained(widget)), false);
+ widget->Restore();
+ EXPECT_TRUE(restore_widget_waiter.Wait());
+ EXPECT_TRUE(widget->IsVisible());
+
+ PropertyWaiter minimize_hwnd_waiter(
+ base::Bind(&Widget::IsMinimized, base::Unretained(widget)), true);
+ CloseWindow(HWNDForWidget(widget));
+ EXPECT_TRUE(minimize_hwnd_waiter.Wait());
+ EXPECT_FALSE(widget->IsVisible());
+
+ PropertyWaiter restore_hwnd_waiter(
+ base::Bind(&Widget::IsMinimized, base::Unretained(widget)), false);
+ OpenIcon(HWNDForWidget(widget));
+ EXPECT_TRUE(restore_hwnd_waiter.Wait());
+ EXPECT_TRUE(widget->IsVisible());
+
+ widget->CloseNow();
+}
+#endif // defined(OS_WIN)
+
+// Tests that minimizing a widget causes the gesture_handler
+// to be cleared when the widget is minimized.
+TEST_F(DesktopWidgetTestInteractive, EventHandlersClearedOnWidgetMinimize) {
+ Widget* widget = CreateWidget();
+ ShowSync(widget);
+ ASSERT_FALSE(widget->IsMinimized());
+ View mouse_handler_view;
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget->GetRootView());
+ // This also sets the gesture_handler, and we'll verify that it
+ // gets cleared when the widget is minimized.
+ root_view->SetMouseHandler(&mouse_handler_view);
+ EXPECT_TRUE(GetGestureHandler(root_view));
+
+ widget->Minimize();
+ EXPECT_FALSE(GetGestureHandler(root_view));
+
+ widget->CloseNow();
+}
+
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Tests that when a desktop native widget has modal transient child, it should
// avoid restore focused view itself as the modal transient child window will do
// that, thus avoids having multiple focused view visually (crbug.com/727641).
-TEST_F(WidgetTestInteractive, DesktopNativeWidgetWithModalTransientChild) {
+TEST_F(DesktopWidgetTestInteractive,
+ DesktopNativeWidgetWithModalTransientChild) {
// Create a desktop native Widget for Widget::Deactivate().
Widget* deactivate_widget = CreateWidget();
ShowSync(deactivate_widget);
@@ -1521,19 +1563,8 @@ class CaptureLostTrackingWidget : public Widget {
class WidgetCaptureTest : public ViewsInteractiveUITestBase {
public:
- WidgetCaptureTest() {
- }
-
- ~WidgetCaptureTest() override {}
-
- void SetUp() override {
- // On mus these tests run as part of views::ViewsTestSuite which already
- // does this initialization.
- if (!IsMus())
- ViewsInteractiveUITestBase::SetUp();
- else
- ViewsTestBase::SetUp();
- }
+ WidgetCaptureTest() = default;
+ ~WidgetCaptureTest() override = default;
// Verifies Widget::SetCapture() results in updating native capture along with
// invoking the right Widget function.
@@ -1583,8 +1614,9 @@ class WidgetCaptureTest : public ViewsInteractiveUITestBase {
NativeWidget* CreateNativeWidget(const Widget::InitParams& params,
bool create_desktop_native_widget,
Widget* widget) {
+ // The test base class by default returns DesktopNativeWidgetAura.
if (create_desktop_native_widget)
- return CreatePlatformDesktopNativeWidgetImpl(params, widget, nullptr);
+ return nullptr;
return CreatePlatformNativeWidgetImpl(params, widget, kDefault, nullptr);
}
@@ -1594,13 +1626,16 @@ class WidgetCaptureTest : public ViewsInteractiveUITestBase {
// See description in TestCapture().
TEST_F(WidgetCaptureTest, Capture) {
- // TODO: capture isn't global in mus. http://crbug.com/678057.
- if (IsMus())
- return;
-
TestCapture(false);
}
+#if !defined(OS_CHROMEOS)
+// See description in TestCapture(). Creates DesktopNativeWidget.
+TEST_F(WidgetCaptureTest, CaptureDesktopNativeWidget) {
+ TestCapture(true);
+}
+#endif
+
// Tests to ensure capture is correctly released from a Widget with capture when
// it is destroyed. Test for crbug.com/622201.
TEST_F(WidgetCaptureTest, DestroyWithCapture_CloseNow) {
@@ -1608,7 +1643,6 @@ TEST_F(WidgetCaptureTest, DestroyWithCapture_CloseNow) {
CaptureLostTrackingWidget* widget =
new CaptureLostTrackingWidget(&capture_state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.native_widget = CreateNativeWidget(params, true, widget);
widget->Init(params);
widget->Show();
@@ -1625,7 +1659,6 @@ TEST_F(WidgetCaptureTest, DestroyWithCapture_Close) {
CaptureLostTrackingWidget* widget =
new CaptureLostTrackingWidget(&capture_state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.native_widget = CreateNativeWidget(params, true, widget);
widget->Init(params);
widget->Show();
@@ -1639,7 +1672,6 @@ TEST_F(WidgetCaptureTest, DestroyWithCapture_Close) {
TEST_F(WidgetCaptureTest, DestroyWithCapture_WidgetOwnsNativeWidget) {
Widget widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.native_widget = CreateNativeWidget(params, true, &widget);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(params);
widget.Show();
@@ -1648,20 +1680,8 @@ TEST_F(WidgetCaptureTest, DestroyWithCapture_WidgetOwnsNativeWidget) {
EXPECT_TRUE(widget.HasCapture());
}
-#if !defined(OS_CHROMEOS)
-// See description in TestCapture(). Creates DesktopNativeWidget.
-TEST_F(WidgetCaptureTest, CaptureDesktopNativeWidget) {
- TestCapture(true);
-}
-#endif
-
// Test that no state is set if capture fails.
TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
Widget widget;
Widget::InitParams params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
@@ -1684,7 +1704,8 @@ TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) {
EXPECT_FALSE(widget.HasCapture());
widget.Show();
- ui::test::EventGenerator generator(GetContext(), widget.GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(&widget),
+ widget.GetNativeWindow());
generator.set_current_screen_location(gfx::Point(300, 10));
generator.PressLeftButton();
@@ -1707,7 +1728,6 @@ TEST_F(WidgetCaptureTest, MAYBE_MouseExitOnCaptureGrab) {
Widget widget1;
Widget::InitParams params1 =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params1.native_widget = CreateNativeWidget(params1, true, &widget1);
params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget1.Init(params1);
MouseView* mouse_view1 = new MouseView;
@@ -1718,7 +1738,6 @@ TEST_F(WidgetCaptureTest, MAYBE_MouseExitOnCaptureGrab) {
Widget widget2;
Widget::InitParams params2 =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params2.native_widget = CreateNativeWidget(params2, true, &widget2);
params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget2.Init(params2);
widget2.Show();
@@ -1767,15 +1786,9 @@ class CaptureOnActivationObserver : public WidgetObserver {
// Test that setting capture on widget activation of a non-toplevel widget
// (e.g. a bubble on Linux) succeeds.
TEST_F(WidgetCaptureTest, SetCaptureToNonToplevel) {
- // TODO: capture isn't global in mus. http://crbug.com/678057.
- if (IsMus())
- return;
-
Widget toplevel;
Widget::InitParams toplevel_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- toplevel_params.native_widget = CreateNativeWidget(toplevel_params, true,
- &toplevel);
toplevel_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
toplevel.Init(toplevel_params);
toplevel.Show();
@@ -1875,13 +1888,13 @@ TEST_F(WidgetCaptureTest, MouseEventDispatchedToRightWindow) {
}
#endif // defined(OS_WIN)
-class WidgetInputMethodInteractiveTest : public WidgetTestInteractive {
+class WidgetInputMethodInteractiveTest : public DesktopWidgetTestInteractive {
public:
WidgetInputMethodInteractiveTest() {}
// testing::Test:
void SetUp() override {
- WidgetTestInteractive::SetUp();
+ DesktopWidgetTestInteractive::SetUp();
#if defined(OS_WIN)
// On Windows, Widget::Deactivate() works by activating the next topmost
// window on the z-order stack. This only works if there is at least one
@@ -1894,7 +1907,7 @@ class WidgetInputMethodInteractiveTest : public WidgetTestInteractive {
void TearDown() override {
if (deactivate_widget_)
deactivate_widget_->CloseNow();
- WidgetTestInteractive::TearDown();
+ DesktopWidgetTestInteractive::TearDown();
}
private:
@@ -1903,17 +1916,13 @@ class WidgetInputMethodInteractiveTest : public WidgetTestInteractive {
DISALLOW_COPY_AND_ASSIGN(WidgetInputMethodInteractiveTest);
};
-// Test input method focus changes affected by top window activaction.
-TEST_F(WidgetInputMethodInteractiveTest,
#if defined(OS_MACOSX)
- DISABLED_Activation
+#define MAYBE_Activation DISABLED_Activation
#else
- Activation
+#define MAYBE_Activation Activation
#endif
- ) {
- if (IsMus())
- return;
-
+// Test input method focus changes affected by top window activaction.
+TEST_F(WidgetInputMethodInteractiveTest, MAYBE_Activation) {
Widget* widget = CreateWidget();
Textfield* textfield = new Textfield;
widget->GetRootView()->AddChildView(textfield);
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index fe6621a26df..ca9e4962d08 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -42,6 +42,8 @@
#include "ui/aura/window_tree_host.h"
#include "ui/base/view_prop.h"
#include "ui/base/win/window_event_target.h"
+#include "ui/views/test/test_platform_native_widget.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/win/hwnd_util.h"
#endif
@@ -554,10 +556,18 @@ TEST_F(WidgetOwnershipTest,
// Test to verify using various Widget methods doesn't crash when the underlying
// NativeView is destroyed.
//
-class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
+class WidgetWithDestroyedNativeViewTest
+ : public ViewsTestBase,
+ public testing::WithParamInterface<ViewsTestBase::NativeWidgetType> {
public:
- WidgetWithDestroyedNativeViewTest() {}
- ~WidgetWithDestroyedNativeViewTest() override {}
+ WidgetWithDestroyedNativeViewTest() = default;
+ ~WidgetWithDestroyedNativeViewTest() override = default;
+
+ // ViewsTestBase:
+ void SetUp() override {
+ set_native_widget_type(GetParam());
+ ViewsTestBase::SetUp();
+ }
void InvokeWidgetMethods(Widget* widget) {
widget->GetNativeView();
@@ -609,33 +619,23 @@ class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
};
-TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
- {
- Widget widget;
- Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- widget.Init(params);
- widget.Show();
-
- widget.native_widget_private()->CloseNow();
- InvokeWidgetMethods(&widget);
- }
-#if !defined(OS_CHROMEOS)
- {
- Widget widget;
- Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, &widget, nullptr);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- widget.Init(params);
- widget.Show();
-
- widget.native_widget_private()->CloseNow();
- InvokeWidgetMethods(&widget);
- }
-#endif
+TEST_P(WidgetWithDestroyedNativeViewTest, Test) {
+ Widget widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget.Init(params);
+ widget.Show();
+
+ widget.native_widget_private()->CloseNow();
+ InvokeWidgetMethods(&widget);
}
+INSTANTIATE_TEST_CASE_P(
+ PlatformWidgetWithDestroyedNativeViewTest,
+ WidgetWithDestroyedNativeViewTest,
+ ::testing::Values(ViewsTestBase::NativeWidgetType::kDefault,
+ ViewsTestBase::NativeWidgetType::kDesktop));
+
////////////////////////////////////////////////////////////////////////////////
// Widget observer tests.
//
@@ -954,9 +954,24 @@ class MoveTrackingTestDesktopWidgetDelegate : public TestDesktopWidgetDelegate {
} // namespace
+class DesktopWidgetObserverTest : public WidgetObserverTest {
+ public:
+ DesktopWidgetObserverTest() = default;
+ ~DesktopWidgetObserverTest() override = default;
+
+ // WidgetObserverTest:
+ void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+ WidgetObserverTest::SetUp();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopWidgetObserverTest);
+};
+
// An extension to the WidgetBoundsChangedNative test above to ensure move
// notifications propagate to the WidgetDelegate.
-TEST_F(WidgetObserverTest, OnWidgetMovedWhenOriginChangesNative) {
+TEST_F(DesktopWidgetObserverTest, OnWidgetMovedWhenOriginChangesNative) {
MoveTrackingTestDesktopWidgetDelegate delegate;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
delegate.InitWidget(params);
@@ -1024,24 +1039,24 @@ TEST_F(WidgetObserverTest, ClosingOnHiddenParent) {
}
// Test behavior of NativeWidget*::GetWindowPlacement on the native desktop.
-TEST_F(WidgetTest, GetWindowPlacement) {
-#if defined(OS_MACOSX)
- if (base::mac::IsOS10_10())
- return; // Fails when swarmed. http://crbug.com/660582
-#endif
-
- WidgetAutoclosePtr widget;
#if defined(USE_X11)
// On desktop-Linux cheat and use non-desktop widgets. On X11, minimize is
// asynchronous. Also (harder) showing a window doesn't activate it without
// user interaction (or extra steps only done for interactive ui tests).
// Without that, show_state remains in ui::SHOW_STATE_INACTIVE throughout.
// TODO(tapted): Find a nice way to run this with desktop widgets on Linux.
- widget.reset(CreateTopLevelPlatformWidget());
+TEST_F(WidgetTest, GetWindowPlacement) {
#else
- widget.reset(CreateNativeDesktopWidget());
+TEST_F(DesktopWidgetTest, GetWindowPlacement) {
+#endif
+#if defined(OS_MACOSX)
+ if (base::mac::IsOS10_10())
+ return; // Fails when swarmed. http://crbug.com/660582
#endif
+ WidgetAutoclosePtr widget;
+ widget.reset(CreateTopLevelNativeWidget());
+
gfx::Rect expected_bounds(100, 110, 200, 220);
widget->SetBounds(expected_bounds);
widget->Show();
@@ -1100,7 +1115,7 @@ TEST_F(WidgetTest, GetWindowPlacement) {
// Test that widget size constraints are properly applied immediately after
// Init(), and that SetBounds() calls are appropriately clamped.
-TEST_F(WidgetTest, MinimumSizeConstraints) {
+TEST_F(DesktopWidgetTest, MinimumSizeConstraints) {
TestDesktopWidgetDelegate delegate;
gfx::Size minimum_size(100, 100);
const gfx::Size smaller_size(90, 90);
@@ -1215,8 +1230,8 @@ TEST_F(WidgetTest, GetWindowBoundsInScreen) {
#endif
// Test that GetRestoredBounds() returns the original bounds of the window.
-TEST_F(WidgetTest, MAYBE_GetRestoredBounds) {
- WidgetAutoclosePtr toplevel(CreateNativeDesktopWidget());
+TEST_F(DesktopWidgetTest, MAYBE_GetRestoredBounds) {
+ WidgetAutoclosePtr toplevel(CreateTopLevelNativeWidget());
toplevel->Show();
// Initial restored bounds have non-zero size.
EXPECT_FALSE(toplevel->GetRestoredBounds().IsEmpty());
@@ -1279,7 +1294,7 @@ TEST_F(WidgetTest, KeyboardInputEvent) {
// Verifies bubbles result in a focus lost when shown.
// TODO(msw): this tests relies on focus, it needs to be in
// interactive_ui_tests.
-TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
+TEST_F(DesktopWidgetTest, DISABLED_FocusChangesOnBubble) {
// Create a widget, show and activate it and focus the contents view.
View* contents_view = new View;
contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -1288,10 +1303,6 @@ TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
init_params.bounds = gfx::Rect(0, 0, 200, 200);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-#if !defined(OS_CHROMEOS)
- init_params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(init_params, &widget, nullptr);
-#endif
widget.Init(init_params);
widget.SetContentsView(contents_view);
widget.Show();
@@ -1336,7 +1347,7 @@ TEST_F(WidgetTest, BubbleControlsResetOnInit) {
// Test to ensure that after minimize, view width is set to zero. This is only
// the case for desktop widgets on Windows. Other platforms retain the window
// size while minimized.
-TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
+TEST_F(DesktopWidgetTest, TestViewWidthAfterMinimizingWidget) {
// Create a widget.
Widget widget;
Widget::InitParams init_params =
@@ -1345,8 +1356,6 @@ TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
gfx::Rect initial_bounds(0, 0, 300, 400);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(init_params, &widget, nullptr);
widget.Init(init_params);
NonClientView* non_client_view = widget.non_client_view();
NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
@@ -1397,11 +1406,7 @@ class DesktopAuraTestValidPaintWidget : public Widget, public WidgetObserver {
quit_closure_ = base::Closure();
}
- // Widget:
- void Close() override {
- expect_paint_ = false;
- views::Widget::Close();
- }
+ void OnWidgetClosing(Widget* widget) override { expect_paint_ = false; }
void OnNativeWidgetPaint(const ui::PaintContext& context) override {
received_paint_ = true;
@@ -1430,8 +1435,6 @@ class DesktopAuraTestValidPaintWidget : public Widget, public WidgetObserver {
void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
init_params.bounds = gfx::Rect(0, 0, 200, 200);
init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(init_params, this, nullptr);
Init(init_params);
View* contents_view = new View;
@@ -1442,7 +1445,7 @@ void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
Activate();
}
-TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
+TEST_F(DesktopWidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
DesktopAuraTestValidPaintWidget widget;
widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
widget.WaitUntilPaint();
@@ -1454,7 +1457,7 @@ TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
EXPECT_FALSE(widget.received_paint_while_hidden());
}
-TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
+TEST_F(DesktopWidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
DesktopAuraTestValidPaintWidget widget;
widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
widget.WaitUntilPaint();
@@ -1469,7 +1472,7 @@ TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
// Test to ensure that the aura Window's visiblity state is set to visible if
// the underlying widget is hidden and then shown.
-TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
+TEST_F(DesktopWidgetTest, TestWindowVisibilityAfterHide) {
// Create a widget.
Widget widget;
Widget::InitParams init_params =
@@ -1478,8 +1481,6 @@ TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
gfx::Rect initial_bounds(0, 0, 300, 400);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(init_params, &widget, nullptr);
widget.Init(init_params);
NonClientView* non_client_view = widget.non_client_view();
NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
@@ -1723,9 +1724,7 @@ TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
gfx::Point cursor_location(5, 5);
- ui::test::EventGenerator generator(
- IsMus() ? GetRootWindow(widget.get()) : GetContext(),
- widget->GetNativeWindow());
+ ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
generator.MoveMouseTo(cursor_location);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_MOVED));
@@ -1780,9 +1779,7 @@ TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
MousePressEventConsumer consumer;
event_count_view->AddPostTargetHandler(&consumer);
- ui::test::EventGenerator generator(
- IsMus() ? GetRootWindow(widget) : GetContext(),
- widget->GetNativeWindow());
+ ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
generator.PressTouch();
generator.ClickLeftButton();
@@ -1813,9 +1810,7 @@ TEST_F(WidgetTest, MousePressCausesCapture) {
MousePressEventConsumer consumer;
event_count_view->AddPostTargetHandler(&consumer);
- ui::test::EventGenerator generator(
- IsMus() ? GetRootWindow(widget) : GetContext(),
- widget->GetNativeWindow());
+ ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
generator.PressLeftButton();
EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
@@ -1877,9 +1872,8 @@ TEST_F(WidgetTest, CaptureDuringMousePressNotOverridden) {
// Gives explicit capture to |widget2|
CaptureEventConsumer consumer(widget2);
event_count_view->AddPostTargetHandler(&consumer);
- ui::test::EventGenerator generator(
- IsMus() ? GetRootWindow(widget) : GetContext(),
- widget->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget),
+ widget->GetNativeWindow());
// This event should implicitly give capture to |widget|, except that
// |consumer| will explicitly set capture on |widget2|.
generator.PressLeftButton();
@@ -1957,9 +1951,7 @@ TEST_F(WidgetTest, DestroyedWithCaptureViaEventMonitor) {
&closing_event_observer, widget->GetNativeWindow(),
{ui::ET_MOUSE_PRESSED});
- ui::test::EventGenerator generator(
- IsMus() ? GetRootWindow(widget) : GetContext(),
- widget->GetNativeWindow());
+ ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
generator.set_target(ui::test::EventGenerator::Target::APPLICATION);
EXPECT_FALSE(observer.widget_closed());
@@ -1981,7 +1973,7 @@ void TestNativeWidgetDestroyedWidget::OnNativeWidgetDestroyed() {
// Verifies that widget destroyed itself in OnNativeWidgetDestroyed does not
// crash in ASan.
-TEST_F(WidgetTest, WidgetDestroyedItselfDoesNotCrash) {
+TEST_F(DesktopWidgetTest, WidgetDestroyedItselfDoesNotCrash) {
TestDesktopWidgetDelegate delegate(new TestNativeWidgetDestroyedWidget);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
@@ -1992,7 +1984,7 @@ TEST_F(WidgetTest, WidgetDestroyedItselfDoesNotCrash) {
// Verifies WindowClosing() is invoked correctly on the delegate when a Widget
// is closed.
-TEST_F(WidgetTest, SingleWindowClosing) {
+TEST_F(DesktopWidgetTest, SingleWindowClosing) {
TestDesktopWidgetDelegate delegate;
delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
EXPECT_EQ(0, delegate.window_closing_count());
@@ -2000,21 +1992,68 @@ TEST_F(WidgetTest, SingleWindowClosing) {
EXPECT_EQ(1, delegate.window_closing_count());
}
-class WidgetWindowTitleTest : public WidgetTest {
+TEST_F(DesktopWidgetTest, CloseRequested_AllowsClose) {
+ constexpr Widget::ClosedReason kReason = Widget::ClosedReason::kLostFocus;
+ TestDesktopWidgetDelegate delegate;
+ delegate.set_can_close(true);
+ delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
+ WidgetDestroyedWaiter waiter(delegate.GetWidget());
+
+ delegate.GetWidget()->CloseWithReason(kReason);
+ EXPECT_TRUE(delegate.GetWidget()->IsClosed());
+ EXPECT_EQ(kReason, delegate.GetWidget()->closed_reason());
+ EXPECT_EQ(kReason, delegate.last_closed_reason());
+
+ waiter.Wait();
+}
+
+TEST_F(DesktopWidgetTest, CloseRequested_DisallowClose) {
+ constexpr Widget::ClosedReason kReason = Widget::ClosedReason::kLostFocus;
+ TestDesktopWidgetDelegate delegate;
+ delegate.set_can_close(false);
+ delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
+
+ delegate.GetWidget()->CloseWithReason(kReason);
+ EXPECT_FALSE(delegate.GetWidget()->IsClosed());
+ EXPECT_EQ(Widget::ClosedReason::kUnspecified,
+ delegate.GetWidget()->closed_reason());
+ EXPECT_EQ(kReason, delegate.last_closed_reason());
+
+ delegate.GetWidget()->CloseNow();
+}
+
+TEST_F(DesktopWidgetTest, CloseRequested_SecondCloseIgnored) {
+ constexpr Widget::ClosedReason kReason1 = Widget::ClosedReason::kLostFocus;
+ constexpr Widget::ClosedReason kReason2 = Widget::ClosedReason::kUnspecified;
+ TestDesktopWidgetDelegate delegate;
+ delegate.set_can_close(true);
+ delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
+ WidgetDestroyedWaiter waiter(delegate.GetWidget());
+
+ // Close for the first time.
+ delegate.GetWidget()->CloseWithReason(kReason1);
+ EXPECT_TRUE(delegate.GetWidget()->IsClosed());
+ EXPECT_EQ(kReason1, delegate.last_closed_reason());
+
+ // Calling close again should have no effect.
+ delegate.GetWidget()->CloseWithReason(kReason2);
+ EXPECT_TRUE(delegate.GetWidget()->IsClosed());
+ EXPECT_EQ(kReason1, delegate.last_closed_reason());
+
+ waiter.Wait();
+}
+
+class WidgetWindowTitleTest : public DesktopWidgetTest {
protected:
void RunTest(bool desktop_native_widget) {
WidgetAutoclosePtr widget(new Widget()); // Destroyed by CloseNow().
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
-#if !defined(OS_CHROMEOS)
- if (desktop_native_widget)
- init_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- init_params, widget.get(), nullptr);
-#else
- DCHECK(!desktop_native_widget)
- << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
-#endif
+ if (!desktop_native_widget) {
+ init_params.native_widget = CreatePlatformNativeWidgetImpl(
+ init_params, widget.get(), kStubCapture, nullptr);
+ }
widget->Init(init_params);
internal::NativeWidgetPrivate* native_widget =
@@ -2047,14 +2086,11 @@ TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
RunTest(desktop_native_widget);
}
-// DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
-#if !defined(OS_CHROMEOS)
TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
// Override to use a DesktopNativeWidget.
bool desktop_native_widget = true;
RunTest(desktop_native_widget);
}
-#endif // !OS_CHROMEOS
TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
Widget* widget = new Widget;
@@ -2067,9 +2103,7 @@ TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
widget->SetSize(gfx::Size(100, 100));
widget->Show();
- ui::test::EventGenerator generator(
- IsMus() ? GetRootWindow(widget) : GetContext(),
- widget->GetNativeWindow());
+ ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
WidgetDeletionObserver deletion_observer(widget);
generator.PressLeftButton();
@@ -2084,11 +2118,6 @@ TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
#if !defined(OS_MACOSX) || defined(USE_AURA)
TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
Widget* widget = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
@@ -2136,19 +2165,17 @@ bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
Widget::InitParams params(in_params);
// Deletes itself when the Widget is destroyed.
params.delegate = new GetNativeThemeFromDestructorView;
-#if !defined(OS_CHROMEOS)
- if (is_first_run) {
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, widget.get(), nullptr);
+ if (!is_first_run) {
+ params.native_widget = CreatePlatformNativeWidgetImpl(
+ params, widget.get(), kStubCapture, nullptr);
needs_second_run = true;
}
-#endif
widget->Init(params);
return needs_second_run;
}
// See description of RunGetNativeThemeFromDestructor() for details.
-TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
+TEST_F(DesktopWidgetTest, GetNativeThemeFromDestructor) {
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
if (RunGetNativeThemeFromDestructor(params, true))
RunGetNativeThemeFromDestructor(params, false);
@@ -2217,16 +2244,12 @@ class WidgetBoundsObserver : public WidgetObserver {
};
// Verifies Close() results in destroying.
-TEST_F(WidgetTest, CloseDestroys) {
+TEST_F(DesktopWidgetTest, CloseDestroys) {
bool destroyed = false;
CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_MENU);
params.opacity = Widget::InitParams::OPAQUE_WINDOW;
-#if !defined(OS_CHROMEOS)
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, widget, nullptr);
-#endif
widget->Init(params);
widget->Show();
widget->Hide();
@@ -2276,9 +2299,9 @@ TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
// ChromeOS doesn't implement or need CloseAllSecondaryWidgets() since
// everything is under a single root window.
#if !defined(OS_CHROMEOS)
-TEST_F(WidgetTest, CloseAllSecondaryWidgets) {
- Widget* widget1 = CreateNativeDesktopWidget();
- Widget* widget2 = CreateNativeDesktopWidget();
+TEST_F(DesktopWidgetTest, CloseAllSecondaryWidgets) {
+ Widget* widget1 = CreateTopLevelNativeWidget();
+ Widget* widget2 = CreateTopLevelNativeWidget();
TestWidgetObserver observer1(widget1);
TestWidgetObserver observer2(widget2);
widget1->Show(); // Just show the first one.
@@ -2290,8 +2313,8 @@ TEST_F(WidgetTest, CloseAllSecondaryWidgets) {
// Test that the NativeWidget is still valid during OnNativeWidgetDestroying(),
// and properties that depend on it are valid, when closed via CloseNow().
-TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromCloseNow) {
- Widget* widget = CreateNativeDesktopWidget();
+TEST_F(DesktopWidgetTest, ValidDuringOnNativeWidgetDestroyingFromCloseNow) {
+ Widget* widget = CreateTopLevelNativeWidget();
widget->Show();
gfx::Rect screen_rect(50, 50, 100, 100);
widget->SetBounds(screen_rect);
@@ -2303,8 +2326,8 @@ TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromCloseNow) {
// Test that the NativeWidget is still valid during OnNativeWidgetDestroying(),
// and properties that depend on it are valid, when closed via Close().
-TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) {
- Widget* widget = CreateNativeDesktopWidget();
+TEST_F(DesktopWidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) {
+ Widget* widget = CreateTopLevelNativeWidget();
widget->Show();
gfx::Rect screen_rect(50, 50, 100, 100);
widget->SetBounds(screen_rect);
@@ -2339,11 +2362,6 @@ TEST_F(WidgetTest, NoCrashOnResizeConstraintsWindowTitleOnPopup) {
// Tests that we do not crash when a Widget is destroyed before it finishes
// processing of pending input events in the message loop.
TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
std::unique_ptr<Widget> widget(new Widget);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
@@ -3176,9 +3194,9 @@ class DestroyedTrackingView : public View {
DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
};
-class WidgetChildDestructionTest : public WidgetTest {
+class WidgetChildDestructionTest : public DesktopWidgetTest {
public:
- WidgetChildDestructionTest() {}
+ WidgetChildDestructionTest() = default;
// Creates a top level and a child, destroys the child and verifies the views
// of the child are destroyed before the views of the parent.
@@ -3190,12 +3208,10 @@ class WidgetChildDestructionTest : public WidgetTest {
Widget* top_level = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
-#if !defined(OS_CHROMEOS)
- if (top_level_has_desktop_native_widget_aura) {
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, top_level, nullptr);
+ if (!top_level_has_desktop_native_widget_aura) {
+ params.native_widget = CreatePlatformNativeWidgetImpl(
+ params, top_level, kStubCapture, nullptr);
}
-#endif
top_level->Init(params);
top_level->GetRootView()->AddChildView(
new DestroyedTrackingView("parent", &destroyed));
@@ -3205,12 +3221,10 @@ class WidgetChildDestructionTest : public WidgetTest {
Widget::InitParams child_params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
child_params.parent = top_level->GetNativeView();
-#if !defined(OS_CHROMEOS)
- if (child_has_desktop_native_widget_aura) {
- child_params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(child_params, child, nullptr);
+ if (!child_has_desktop_native_widget_aura) {
+ child_params.native_widget = CreatePlatformNativeWidgetImpl(
+ child_params, child, kStubCapture, nullptr);
}
-#endif
child->Init(child_params);
child->GetRootView()->AddChildView(
new DestroyedTrackingView("child", &destroyed));
@@ -3270,15 +3284,13 @@ TEST_F(WidgetTest, FullscreenStatePropagated) {
// Verifies nativeview visbility matches that of Widget visibility when
// SetFullscreen is invoked, for a widget provided with a desktop widget.
#if !defined(OS_CHROMEOS)
-TEST_F(WidgetTest, FullscreenStatePropagated_DesktopWidget) {
+TEST_F(DesktopWidgetTest, FullscreenStatePropagated_DesktopWidget) {
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.show_state = ui::SHOW_STATE_NORMAL;
init_params.bounds = gfx::Rect(0, 0, 500, 500);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
Widget top_level_widget;
- init_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- init_params, &top_level_widget, nullptr);
top_level_widget.Init(init_params);
top_level_widget.SetFullscreen(true);
@@ -3303,7 +3315,7 @@ class FullscreenAwareFrame : public views::NonClientFrameView {
return gfx::Rect();
}
int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
- void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {}
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {}
void ResetWindowControls() override {}
void UpdateWindowIcon() override {}
void UpdateWindowTitle() override {}
@@ -3363,14 +3375,12 @@ class IsActiveFromDestroyObserver : public WidgetObserver {
// Verifies Widget::IsActive() invoked from
// WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
-TEST_F(WidgetTest, IsActiveFromDestroy) {
+TEST_F(DesktopWidgetTest, IsActiveFromDestroy) {
// Create two widgets, one a child of the other.
IsActiveFromDestroyObserver observer;
Widget parent_widget;
Widget::InitParams parent_params =
CreateParams(Widget::InitParams::TYPE_POPUP);
- parent_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- parent_params, &parent_widget, nullptr);
parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
parent_widget.Init(parent_params);
parent_widget.Show();
@@ -3391,11 +3401,6 @@ TEST_F(WidgetTest, IsActiveFromDestroy) {
// Tests that events propagate through from the dispatcher with the correct
// event type, and that the different platforms behave the same.
TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
EventCountView* view = new EventCountView;
view->set_handle_mode(EventCountView::CONSUME_EVENTS);
view->SetBounds(10, 10, 50, 40);
@@ -3562,12 +3567,10 @@ SubclassWindowHelper* SubclassWindowHelper::instance_ = nullptr;
// 2. Posting a WM_NCMOUSEMOVE message with a different hittest code.
// 3. Posting a WM_MOUSEMOVE message.
// Disabled because of flaky timeouts: http://crbug.com/592742
-TEST_F(WidgetTest, DISABLED_SysCommandMoveOnNCLButtonDownOnCaptionAndMoveTest) {
+TEST_F(DesktopWidgetTest,
+ DISABLED_SysCommandMoveOnNCLButtonDownOnCaptionAndMoveTest) {
Widget widget;
- Widget::InitParams params =
- CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, &widget, nullptr);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(params);
widget.SetBounds(gfx::Rect(0, 0, 200, 200));
@@ -3597,7 +3600,7 @@ TEST_F(WidgetTest, DISABLED_SysCommandMoveOnNCLButtonDownOnCaptionAndMoveTest) {
EXPECT_FALSE(subclass_helper.received_message(WM_SYSCOMMAND));
subclass_helper.Clear();
- // Posting a WM_NCLBUTTONDOWN message followed by a WM_NCMOUSEMOVE at a
+ // Posting a WM_NCLBUTTONDOWN message followed by a WM_NCMOUSEMOVE at a
// different location should result in a WM_SYSCOMMAND message.
::PostMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(100, 100));
::PostMessage(window, WM_NCMOUSEMOVE, HTCAPTION, MAKELPARAM(110, 110));
@@ -3608,7 +3611,7 @@ TEST_F(WidgetTest, DISABLED_SysCommandMoveOnNCLButtonDownOnCaptionAndMoveTest) {
EXPECT_TRUE(subclass_helper.received_message(WM_SYSCOMMAND));
subclass_helper.Clear();
- // Posting a WM_NCLBUTTONDOWN message followed by a WM_NCMOUSEMOVE at a
+ // Posting a WM_NCLBUTTONDOWN message followed by a WM_NCMOUSEMOVE at a
// different location with a different hittest code should result in a
// WM_SYSCOMMAND message.
::PostMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(100, 100));
@@ -3636,12 +3639,10 @@ TEST_F(WidgetTest, DISABLED_SysCommandMoveOnNCLButtonDownOnCaptionAndMoveTest) {
// This test validates that destroying the window in the context of the
// WM_SYSCOMMAND message with SC_MOVE does not crash.
// Disabled because of flaky timeouts: http://crbug.com/592742
-TEST_F(WidgetTest, DISABLED_DestroyInSysCommandNCLButtonDownOnCaption) {
+TEST_F(DesktopWidgetTest, DISABLED_DestroyInSysCommandNCLButtonDownOnCaption) {
Widget widget;
Widget::InitParams params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(params, &widget, nullptr);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(params);
widget.SetBounds(gfx::Rect(0, 0, 200, 200));
@@ -3704,11 +3705,6 @@ class ScaleFactorView : public View {
// Ensure scale factor changes are propagated from the native Widget.
TEST_F(WidgetTest, OnDeviceScaleFactorChanged) {
- // This relies on the NativeWidget being the WindowDelegate, which is not the
- // case for aura-mus-client.
- if (IsMus())
- return;
-
// Automatically close the widget, but not delete it.
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
ScaleFactorView* view = new ScaleFactorView;
@@ -3814,11 +3810,6 @@ TEST_F(WidgetTest, WidgetRemovalsObserverCalledWhenMovingBetweenWidgets) {
// Test dispatch of ui::ET_MOUSEWHEEL.
TEST_F(WidgetTest, MouseWheelEvent) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->SetBounds(gfx::Rect(0, 0, 600, 600));
EventCountView* event_count_view = new EventCountView();
@@ -3835,9 +3826,24 @@ TEST_F(WidgetTest, MouseWheelEvent) {
class WidgetShadowTest : public WidgetTest {
public:
- WidgetShadowTest() { InitControllers(); }
+ WidgetShadowTest() = default;
+ ~WidgetShadowTest() override = default;
// WidgetTest:
+ void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+ WidgetTest::SetUp();
+ InitControllers();
+ }
+
+ void TearDown() override {
+#if defined(OS_CHROMEOS)
+ shadow_controller_.reset();
+ focus_controller_.reset();
+#endif
+ WidgetTest::TearDown();
+ }
+
Widget::InitParams CreateParams(Widget::InitParams::Type type) override {
Widget::InitParams params =
WidgetTest::CreateParams(override_type_.value_or(type));
@@ -3861,7 +3867,7 @@ class WidgetShadowTest : public WidgetTest {
public:
TestFocusRules() = default;
- bool SupportsChildActivation(aura::Window* window) const override {
+ bool SupportsChildActivation(const aura::Window* window) const override {
return true;
}
@@ -3870,11 +3876,6 @@ class WidgetShadowTest : public WidgetTest {
};
void InitControllers() {
- // Add bits usually managed by the ash::Shell. Under Mus,
- // DesktopNativeWidgetAura provides these in-process instead.
- if (IsMus())
- return;
-
focus_controller_ =
std::make_unique<wm::FocusController>(new TestFocusRules);
shadow_controller_ = std::make_unique<wm::ShadowController>(
@@ -3902,23 +3903,16 @@ TEST_F(WidgetShadowTest, MAYBE_ShadowsInRootWindow) {
// A desktop window clips to its bounds, so it shouldn't have a shadow.
bool top_level_window_should_have_shadow = false;
-#if defined(OS_CHROMEOS)
- // In Mus, the shadow should be in the WindowServer process only. In non-mus
- // CreateNativeDesktopWidget() creates a non-root window, so it should have
- // a shadow.
- top_level_window_should_have_shadow = !IsMus();
-#endif
-
// To start, just create a Widget. This constructs the first ShadowController
// which will start observing the environment for additional aura::Window
// initialization. The very first ShadowController in DesktopNativeWidgetAura
// is created after the call to aura::Window::Init(), so the ShadowController
// Impl class won't ever see this first Window being initialized.
name_ = "other_top_level";
- Widget* other_top_level = CreateNativeDesktopWidget();
+ Widget* other_top_level = CreateTopLevelNativeWidget();
name_ = "top_level";
- Widget* top_level = CreateNativeDesktopWidget();
+ Widget* top_level = CreateTopLevelNativeWidget();
top_level->SetBounds(gfx::Rect(100, 100, 320, 200));
EXPECT_FALSE(WidgetHasInProcessShadow(top_level));
@@ -3993,20 +3987,18 @@ private:
// Tests the case where an intervening owner popup window is destroyed out from
// under the currently active modal top-level window. In this instance, the
// remaining top-level windows should be re-enabled.
-TEST_F(WidgetTest, WindowModalOwnerDestroyedEnabledTest) {
+TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) {
// top_level_widget owns owner_dialog_widget which owns owned_dialog_widget.
Widget top_level_widget;
Widget owner_dialog_widget;
Widget owned_dialog_widget;
// Create the top level widget.
Widget::InitParams init_params =
- CreateParams(Widget::InitParams::TYPE_WINDOW);
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.show_state = ui::SHOW_STATE_NORMAL;
gfx::Rect initial_bounds(0, 0, 500, 500);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- init_params, &top_level_widget, nullptr);
top_level_widget.Init(init_params);
top_level_widget.Show();
@@ -4014,7 +4006,7 @@ TEST_F(WidgetTest, WindowModalOwnerDestroyedEnabledTest) {
// owner_dialog_delegate instance will be destroyed when the dialog
// is destroyed.
ModalDialogDelegate* owner_dialog_delegate =
- new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
+ new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
init_params = CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.show_state = ui::SHOW_STATE_NORMAL;
@@ -4022,8 +4014,9 @@ TEST_F(WidgetTest, WindowModalOwnerDestroyedEnabledTest) {
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
init_params.delegate = owner_dialog_delegate;
init_params.parent = top_level_widget.GetNativeView();
- init_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- init_params, &owner_dialog_widget, nullptr);
+ init_params.native_widget =
+ new test::TestPlatformNativeWidget<DesktopNativeWidgetAura>(
+ &owner_dialog_widget, false, nullptr);
owner_dialog_widget.Init(init_params);
HWND owner_hwnd = HWNDForWidget(&owner_dialog_widget);
@@ -4034,7 +4027,7 @@ TEST_F(WidgetTest, WindowModalOwnerDestroyedEnabledTest) {
// As above, the owned_dialog_instance instance will be destroyed
// when the dialog is destroyed.
ModalDialogDelegate* owned_dialog_delegate =
- new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
+ new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
init_params = CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.show_state = ui::SHOW_STATE_NORMAL;
@@ -4042,13 +4035,15 @@ TEST_F(WidgetTest, WindowModalOwnerDestroyedEnabledTest) {
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
init_params.delegate = owned_dialog_delegate;
init_params.parent = owner_dialog_widget.GetNativeView();
- init_params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
- init_params, &owned_dialog_widget, nullptr);
+ init_params.native_widget =
+ new test::TestPlatformNativeWidget<DesktopNativeWidgetAura>(
+ &owned_dialog_widget, false, nullptr);
owned_dialog_widget.Init(init_params);
HWND owned_hwnd = HWNDForWidget(&owned_dialog_widget);
owned_dialog_widget.Show();
+ RunPendingMessages();
HWND top_hwnd = HWNDForWidget(&top_level_widget);
@@ -4057,6 +4052,7 @@ TEST_F(WidgetTest, WindowModalOwnerDestroyedEnabledTest) {
EXPECT_TRUE(!!IsWindowEnabled(owned_hwnd));
owner_dialog_widget.CloseNow();
+ RunPendingMessages();
EXPECT_FALSE(!!IsWindow(owner_hwnd));
EXPECT_FALSE(!!IsWindow(owned_hwnd));
@@ -4079,16 +4075,13 @@ void InitializeWidgetForOpacity(
init_params.show_state = ui::SHOW_STATE_NORMAL;
init_params.bounds = gfx::Rect(0, 0, 500, 500);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget =
- CreatePlatformDesktopNativeWidgetImpl(init_params, &widget, nullptr);
widget.Init(init_params);
}
-class CompositingWidgetTest : public views::test::WidgetTest {
+class CompositingWidgetTest : public DesktopWidgetTest {
public:
CompositingWidgetTest()
: widget_types_{Widget::InitParams::TYPE_WINDOW,
- Widget::InitParams::TYPE_PANEL,
Widget::InitParams::TYPE_WINDOW_FRAMELESS,
Widget::InitParams::TYPE_CONTROL,
Widget::InitParams::TYPE_POPUP,
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index 322315fb109..f3523d2a05c 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -24,6 +24,7 @@
#include "base/trace_event/trace_event.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/windows_version.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/accessibility/platform/ax_platform_node_win.h"
#include "ui/accessibility/platform/ax_system_caret_win.h"
#include "ui/base/ime/input_method.h"
@@ -47,7 +48,6 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/icon_util.h"
-#include "ui/gfx/path.h"
#include "ui/gfx/path_win.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/gfx/win/rendering_window_manager.h"
@@ -397,7 +397,6 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
pen_processor_(
&id_generator_,
base::FeatureList::IsEnabled(features::kDirectManipulationStylus)),
- in_size_loop_(false),
touch_down_contexts_(0),
last_mouse_hwheel_time_(0),
dwm_transition_desired_(false),
@@ -1425,7 +1424,7 @@ void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) {
OffsetRect(&work_rect, -window_rect.left, -window_rect.top);
new_region.reset(CreateRectRgnIndirect(&work_rect));
} else {
- gfx::Path window_mask;
+ SkPath window_mask;
delegate_->GetWindowMask(gfx::Size(window_rect.right - window_rect.left,
window_rect.bottom - window_rect.top),
&window_mask);
@@ -2404,6 +2403,10 @@ void HWNDMessageHandler::OnSettingChange(UINT flags, const wchar_t* section) {
}
void HWNDMessageHandler::OnSize(UINT param, const gfx::Size& size) {
+ if (DidMinimizedChange(last_size_param_, param) && IsTopLevelWindow(hwnd()))
+ delegate_->HandleWindowMinimizedOrRestored(param != SIZE_MINIMIZED);
+ last_size_param_ = param;
+
RedrawWindow(hwnd(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
// ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
// invoked OnSize we ensure the RootView has been laid out.
@@ -2474,22 +2477,12 @@ void HWNDMessageHandler::OnSysCommand(UINT notification_code,
return;
}
+ if (delegate_->HandleCommand(notification_code))
+ return;
+
// If the delegate can't handle it, the system implementation will be called.
- if (!delegate_->HandleCommand(notification_code)) {
- // If the window is being resized by dragging the borders of the window
- // with the mouse/touch/keyboard, we flag as being in a size loop.
- if ((notification_code & sc_mask) == SC_SIZE)
- in_size_loop_ = true;
- base::WeakPtr<HWNDMessageHandler> ref(
- msg_handler_weak_factory_.GetWeakPtr());
-
- DefWindowProc(hwnd(), WM_SYSCOMMAND, notification_code,
- MAKELPARAM(point.x(), point.y()));
-
- if (!ref.get())
- return;
- in_size_loop_ = false;
- }
+ DefWindowProc(hwnd(), WM_SYSCOMMAND, notification_code,
+ MAKELPARAM(point.x(), point.y()));
}
void HWNDMessageHandler::OnThemeChanged() {
@@ -2737,9 +2730,9 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
window_pos->flags &= ~SWP_SHOWWINDOW;
}
- if (window_pos->flags & SWP_SHOWWINDOW)
+ if (window_pos->flags & SWP_SHOWWINDOW) {
delegate_->HandleVisibilityChanging(true);
- else if (window_pos->flags & SWP_HIDEWINDOW) {
+ } else if (window_pos->flags & SWP_HIDEWINDOW) {
SetDwmFrameExtension(DwmFrameState::OFF);
delegate_->HandleVisibilityChanging(false);
}
@@ -3129,8 +3122,10 @@ void HWNDMessageHandler::PerformDwmTransition() {
// 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;
+ // not calling this unless DWM composition actually changes. Finally, since
+ // we don't want windows stealing focus if they're not already active, we
+ // set SWP_NOACTIVATE.
+ UINT flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE;
SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_HIDEWINDOW);
SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_SHOWWINDOW);
}
diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h
index c0f8d689ffd..10c2fcd1742 100644
--- a/chromium/ui/views/win/hwnd_message_handler.h
+++ b/chromium/ui/views/win/hwnd_message_handler.h
@@ -642,6 +642,9 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// activation, etc.)
bool ignore_window_pos_changes_;
+ // Keeps track of the last size type param received from a WM_SIZE message.
+ UINT last_size_param_ = SIZE_RESTORED;
+
// The last-seen monitor containing us, and its rect and work area. These are
// used to catch updates to the rect and work area and react accordingly.
HMONITOR last_monitor_;
@@ -661,9 +664,6 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
PenEventProcessor pen_processor_;
- // Set to true if we are in the context of a sizing operation.
- bool in_size_loop_;
-
// Stores a pointer to the WindowEventTarget interface implemented by this
// class. Allows callers to retrieve the interface pointer.
std::unique_ptr<ui::ViewProp> prop_window_target_;
diff --git a/chromium/ui/views/win/hwnd_message_handler_delegate.h b/chromium/ui/views/win/hwnd_message_handler_delegate.h
index 690bc7aedd2..a3c4e34bd26 100644
--- a/chromium/ui/views/win/hwnd_message_handler_delegate.h
+++ b/chromium/ui/views/win/hwnd_message_handler_delegate.h
@@ -10,9 +10,10 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
+class SkPath;
+
namespace gfx {
class Insets;
-class Path;
class Point;
class Rect;
class Size;
@@ -82,7 +83,7 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
virtual bool WillProcessWorkAreaChange() const = 0;
virtual int GetNonClientComponent(const gfx::Point& point) const = 0;
- virtual void GetWindowMask(const gfx::Size& size, gfx::Path* mask) = 0;
+ virtual void GetWindowMask(const gfx::Size& size, SkPath* mask) = 0;
// Returns true if the delegate modifies |insets| to define a custom client
// area for the window, false if the default client area should be used. If
@@ -179,6 +180,9 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// Called when the window's visibility changed. |visible| holds the new state.
virtual void HandleVisibilityChanged(bool visible) = 0;
+ // Called when a top level window is minimized or restored.
+ virtual void HandleWindowMinimizedOrRestored(bool restored) = 0;
+
// Called when the window's client size changed. |new_size| holds the new
// size.
virtual void HandleClientSizeChanged(const gfx::Size& new_size) = 0;
diff --git a/chromium/ui/views/window/caption_button_layout_constants.cc b/chromium/ui/views/window/caption_button_layout_constants.cc
new file mode 100644
index 00000000000..ff8a96d6e72
--- /dev/null
+++ b/chromium/ui/views/window/caption_button_layout_constants.cc
@@ -0,0 +1,26 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/window/caption_button_layout_constants.h"
+
+#include "base/logging.h"
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace views {
+
+gfx::Size GetCaptionButtonLayoutSize(CaptionButtonLayoutSize size) {
+ if (size == CaptionButtonLayoutSize::kNonBrowserCaption)
+ return gfx::Size(kCaptionButtonWidth, 32);
+
+ // |kBrowserMaximizedCaptionButtonHeight| should be kept in sync with those
+ // for TAB_HEIGHT in // chrome/browser/ui/layout_constants.cc.
+ // TODO: Ideally these values should be obtained from a common location.
+ int height = ui::MaterialDesignController::touch_ui() ? 41 : 34;
+ if (size == CaptionButtonLayoutSize::kBrowserCaptionRestored)
+ height += 8; // Restored window titlebars are 8 DIP taller than maximized.
+ return gfx::Size(kCaptionButtonWidth, height);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/window/caption_button_layout_constants.h b/chromium/ui/views/window/caption_button_layout_constants.h
new file mode 100644
index 00000000000..9c354fc1ed2
--- /dev/null
+++ b/chromium/ui/views/window/caption_button_layout_constants.h
@@ -0,0 +1,39 @@
+// 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_WINDOW_CAPTION_BUTTON_LAYOUT_CONSTANTS_H_
+#define UI_VIEWS_WINDOW_CAPTION_BUTTON_LAYOUT_CONSTANTS_H_
+
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Size;
+} // namespace gfx
+
+namespace views {
+
+enum class CaptionButtonLayoutSize {
+ // Size of a caption button in a maximized browser window.
+ kBrowserCaptionMaximized,
+
+ // Size of a caption button in a restored browser window.
+ kBrowserCaptionRestored,
+
+ // Size of a caption button in a non-browser window.
+ kNonBrowserCaption,
+};
+
+// Default radius of caption button ink drop highlight and mask.
+constexpr int kCaptionButtonInkDropDefaultCornerRadius = 14;
+
+// Caption button width.
+constexpr int kCaptionButtonWidth = 32;
+
+// Calculates the preferred size of an MD-style frame caption button. Only used
+// on ChromeOS and desktop Linux.
+VIEWS_EXPORT gfx::Size GetCaptionButtonLayoutSize(CaptionButtonLayoutSize size);
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_CAPTION_BUTTON_LAYOUT_CONSTANTS_H_
diff --git a/chromium/ui/views/window/caption_button_types.h b/chromium/ui/views/window/caption_button_types.h
new file mode 100644
index 00000000000..12b41c08068
--- /dev/null
+++ b/chromium/ui/views/window/caption_button_types.h
@@ -0,0 +1,27 @@
+// 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_WINDOW_CAPTION_BUTTON_TYPES_H_
+#define UI_VIEWS_WINDOW_CAPTION_BUTTON_TYPES_H_
+
+namespace views {
+
+// These are the icon types that a caption button can have. The size button's
+// action (SnapType) can be different from its icon.
+enum CaptionButtonIcon {
+ CAPTION_BUTTON_ICON_MINIMIZE,
+ CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE,
+ CAPTION_BUTTON_ICON_CLOSE,
+ CAPTION_BUTTON_ICON_LEFT_SNAPPED,
+ CAPTION_BUTTON_ICON_RIGHT_SNAPPED,
+ CAPTION_BUTTON_ICON_BACK,
+ CAPTION_BUTTON_ICON_LOCATION,
+ CAPTION_BUTTON_ICON_MENU,
+ CAPTION_BUTTON_ICON_ZOOM,
+ CAPTION_BUTTON_ICON_COUNT
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_CAPTION_BUTTON_TYPES_H_
diff --git a/chromium/ui/views/window/custom_frame_view.cc b/chromium/ui/views/window/custom_frame_view.cc
index 01a5c58eb39..fc08c300053 100644
--- a/chromium/ui/views/window/custom_frame_view.cc
+++ b/chromium/ui/views/window/custom_frame_view.cc
@@ -9,6 +9,7 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
@@ -16,7 +17,6 @@
#include "ui/gfx/font.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/image.h"
-#include "ui/gfx/path.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/resources/grit/views_resources.h"
@@ -175,7 +175,7 @@ int CustomFrameView::NonClientHitTest(const gfx::Point& point) {
}
void CustomFrameView::GetWindowMask(const gfx::Size& size,
- gfx::Path* window_mask) {
+ SkPath* window_mask) {
DCHECK(window_mask);
if (frame_->IsMaximized() || !ShouldShowTitleBarAndBorder())
return;
@@ -274,7 +274,7 @@ gfx::Size CustomFrameView::GetMaximumSize() const {
void CustomFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == close_button_)
- frame_->Close();
+ frame_->CloseWithReason(views::Widget::ClosedReason::kCloseButtonClicked);
else if (sender == minimize_button_)
frame_->Minimize();
else if (sender == maximize_button_)
diff --git a/chromium/ui/views/window/custom_frame_view.h b/chromium/ui/views/window/custom_frame_view.h
index 336447d37c1..a08310f58bb 100644
--- a/chromium/ui/views/window/custom_frame_view.h
+++ b/chromium/ui/views/window/custom_frame_view.h
@@ -41,7 +41,7 @@ class VIEWS_EXPORT CustomFrameView : public NonClientFrameView,
gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const override;
int NonClientHitTest(const gfx::Point& point) override;
- void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override;
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override;
void ResetWindowControls() override;
void UpdateWindowIcon() override;
void UpdateWindowTitle() override;
diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc
index ec17425f17a..48a7d156949 100644
--- a/chromium/ui/views/window/dialog_client_view.cc
+++ b/chromium/ui/views/window/dialog_client_view.cc
@@ -91,7 +91,8 @@ void DialogClientView::AcceptWindow() {
// Only notify the delegate once. See |delegate_allowed_close_|'s comment.
if (!delegate_allowed_close_ && GetDialogDelegate()->Accept()) {
delegate_allowed_close_ = true;
- GetWidget()->Close();
+ GetWidget()->CloseWithReason(
+ views::Widget::ClosedReason::kAcceptButtonClicked);
}
}
@@ -99,7 +100,8 @@ void DialogClientView::CancelWindow() {
// Only notify the delegate once. See |delegate_allowed_close_|'s comment.
if (!delegate_allowed_close_ && GetDialogDelegate()->Cancel()) {
delegate_allowed_close_ = true;
- GetWidget()->Close();
+ GetWidget()->CloseWithReason(
+ views::Widget::ClosedReason::kCancelButtonClicked);
}
}
@@ -184,7 +186,7 @@ void DialogClientView::Layout() {
bool DialogClientView::AcceleratorPressed(const ui::Accelerator& accelerator) {
DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE);
- GetWidget()->Close();
+ GetWidget()->CloseWithReason(Widget::ClosedReason::kEscKeyPressed);
return true;
}
@@ -274,7 +276,7 @@ void DialogClientView::ChildVisibilityChanged(View* child) {
ChildPreferredSizeChanged(child);
}
-void DialogClientView::OnDialogModelChanged() {
+void DialogClientView::OnDialogChanged() {
UpdateDialogButtons();
}
diff --git a/chromium/ui/views/window/dialog_client_view.h b/chromium/ui/views/window/dialog_client_view.h
index 3981e4f8b6c..47c80e6e63a 100644
--- a/chromium/ui/views/window/dialog_client_view.h
+++ b/chromium/ui/views/window/dialog_client_view.h
@@ -88,7 +88,7 @@ class VIEWS_EXPORT DialogClientView : public ClientView,
void ChildVisibilityChanged(View* child) override;
// DialogObserver:
- void OnDialogModelChanged() override;
+ void OnDialogChanged() override;
// Update the dialog buttons to match the dialog's delegate.
void UpdateDialogButtons();
diff --git a/chromium/ui/views/window/dialog_delegate.cc b/chromium/ui/views/window/dialog_delegate.cc
index 4530b5535be..343a50337f8 100644
--- a/chromium/ui/views/window/dialog_delegate.cc
+++ b/chromium/ui/views/window/dialog_delegate.cc
@@ -96,6 +96,35 @@ Widget::InitParams DialogDelegate::GetDialogWidgetInitParams(
return params;
}
+int DialogDelegate::GetDialogButtons() const {
+ return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+}
+
+int DialogDelegate::GetDefaultDialogButton() const {
+ if (GetDialogButtons() & ui::DIALOG_BUTTON_OK)
+ return ui::DIALOG_BUTTON_OK;
+ if (GetDialogButtons() & ui::DIALOG_BUTTON_CANCEL)
+ return ui::DIALOG_BUTTON_CANCEL;
+ return ui::DIALOG_BUTTON_NONE;
+}
+
+base::string16 DialogDelegate::GetDialogButtonLabel(
+ ui::DialogButton button) const {
+ if (button == ui::DIALOG_BUTTON_OK)
+ return l10n_util::GetStringUTF16(IDS_APP_OK);
+ if (button == ui::DIALOG_BUTTON_CANCEL) {
+ if (GetDialogButtons() & ui::DIALOG_BUTTON_OK)
+ return l10n_util::GetStringUTF16(IDS_APP_CANCEL);
+ return l10n_util::GetStringUTF16(IDS_APP_CLOSE);
+ }
+ NOTREACHED();
+ return base::string16();
+}
+
+bool DialogDelegate::IsDialogButtonEnabled(ui::DialogButton button) const {
+ return true;
+}
+
View* DialogDelegate::CreateExtraView() {
return NULL;
}
@@ -140,35 +169,6 @@ bool DialogDelegate::ShouldSnapFrameWidth() const {
return GetDialogButtons() != ui::DIALOG_BUTTON_NONE;
}
-int DialogDelegate::GetDialogButtons() const {
- return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
-}
-
-int DialogDelegate::GetDefaultDialogButton() const {
- if (GetDialogButtons() & ui::DIALOG_BUTTON_OK)
- return ui::DIALOG_BUTTON_OK;
- if (GetDialogButtons() & ui::DIALOG_BUTTON_CANCEL)
- return ui::DIALOG_BUTTON_CANCEL;
- return ui::DIALOG_BUTTON_NONE;
-}
-
-base::string16 DialogDelegate::GetDialogButtonLabel(
- ui::DialogButton button) const {
- if (button == ui::DIALOG_BUTTON_OK)
- return l10n_util::GetStringUTF16(IDS_APP_OK);
- if (button == ui::DIALOG_BUTTON_CANCEL) {
- if (GetDialogButtons() & ui::DIALOG_BUTTON_OK)
- return l10n_util::GetStringUTF16(IDS_APP_CANCEL);
- return l10n_util::GetStringUTF16(IDS_APP_CLOSE);
- }
- NOTREACHED();
- return base::string16();
-}
-
-bool DialogDelegate::IsDialogButtonEnabled(ui::DialogButton button) const {
- return true;
-}
-
View* DialogDelegate::GetInitiallyFocusedView() {
// Focus the default button if any.
const DialogClientView* dcv = GetDialogClientView();
@@ -241,7 +241,7 @@ void DialogDelegate::RemoveObserver(DialogObserver* observer) {
void DialogDelegate::DialogModelChanged() {
for (DialogObserver& observer : observer_list_)
- observer.OnDialogModelChanged();
+ observer.OnDialogChanged();
}
DialogDelegate::~DialogDelegate() {
diff --git a/chromium/ui/views/window/dialog_delegate.h b/chromium/ui/views/window/dialog_delegate.h
index bbba8b1be6e..d1cd016684b 100644
--- a/chromium/ui/views/window/dialog_delegate.h
+++ b/chromium/ui/views/window/dialog_delegate.h
@@ -10,8 +10,8 @@
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "ui/accessibility/ax_enums.mojom.h"
-#include "ui/base/models/dialog_model.h"
#include "ui/base/ui_base_types.h"
+#include "ui/views/views_export.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -31,8 +31,7 @@ class LabelButton;
// certain events.
//
///////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
- public WidgetDelegate {
+class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
public:
DialogDelegate();
@@ -49,6 +48,24 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
gfx::NativeView parent,
const gfx::Rect& bounds);
+ // Returns a mask specifying which of the available DialogButtons are visible
+ // for the dialog. Note: Dialogs with just an OK button are frowned upon.
+ virtual int GetDialogButtons() const;
+
+ // Returns the default dialog button. This should not be a mask as only
+ // one button should ever be the default button. Return
+ // ui::DIALOG_BUTTON_NONE if there is no default. Default
+ // behavior is to return ui::DIALOG_BUTTON_OK or
+ // ui::DIALOG_BUTTON_CANCEL (in that order) if they are
+ // present, ui::DIALOG_BUTTON_NONE otherwise.
+ virtual int GetDefaultDialogButton() const;
+
+ // Returns the label of the specified dialog button.
+ virtual base::string16 GetDialogButtonLabel(ui::DialogButton button) const;
+
+ // Returns whether the specified dialog button is enabled.
+ virtual bool IsDialogButtonEnabled(ui::DialogButton button) const;
+
// Override this function to display an extra view adjacent to the buttons.
// Overrides may construct the view; this will only be called once per dialog.
virtual View* CreateExtraView();
@@ -93,12 +110,6 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
// LayoutProvider's snapping.
virtual bool ShouldSnapFrameWidth() const;
- // Overridden from ui::DialogModel:
- int GetDialogButtons() const override;
- int GetDefaultDialogButton() const override;
- base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
- bool IsDialogButtonEnabled(ui::DialogButton button) const override;
-
// Overridden from WidgetDelegate:
View* GetInitiallyFocusedView() override;
DialogDelegate* AsDialogDelegate() override;
diff --git a/chromium/ui/views/window/dialog_delegate_unittest.cc b/chromium/ui/views/window/dialog_delegate_unittest.cc
index 5fd4c862b0e..a439800f5f7 100644
--- a/chromium/ui/views/window/dialog_delegate_unittest.cc
+++ b/chromium/ui/views/window/dialog_delegate_unittest.cc
@@ -4,7 +4,7 @@
#include <stddef.h>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/hit_test.h"
#include "ui/events/event_processor.h"
@@ -227,7 +227,7 @@ TEST_F(DialogTest, HitTest_HiddenTitle) {
{1000, HTNOWHERE},
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
gfx::Point point(cases[i].point, cases[i].point);
EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
<< " case " << i << " at point " << cases[i].point;
@@ -250,7 +250,7 @@ TEST_F(DialogTest, HitTest_HiddenTitleNoCloseButton) {
{50, HTCLIENT}, {60, HTCLIENT}, {1000, HTNOWHERE},
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
gfx::Point point(cases[i].point, cases[i].point);
EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
<< " case " << i << " at point " << cases[i].point;
@@ -272,7 +272,7 @@ TEST_F(DialogTest, HitTest_WithTitle) {
{50, HTCLIENT}, {60, HTCLIENT}, {1000, HTNOWHERE},
};
- for (size_t i = 0; i < arraysize(cases); ++i) {
+ for (size_t i = 0; i < base::size(cases); ++i) {
gfx::Point point(cases[i].point, cases[i].point);
EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
<< " at point " << cases[i].point;
diff --git a/chromium/ui/views/window/dialog_observer.h b/chromium/ui/views/window/dialog_observer.h
index 95aca714c4a..2b3210f733d 100644
--- a/chromium/ui/views/window/dialog_observer.h
+++ b/chromium/ui/views/window/dialog_observer.h
@@ -9,12 +9,12 @@
namespace views {
-// Allows properties on a ui::DialogModel to be observed.
+// Allows properties on a DialogDelegate to be observed.
class VIEWS_EXPORT DialogObserver {
public:
// Invoked when a dialog signals a model change. E.g., the enabled buttons, or
// the button titles.
- virtual void OnDialogModelChanged() = 0;
+ virtual void OnDialogChanged() = 0;
};
} // namespace views
diff --git a/chromium/ui/views/window/frame_caption_button.cc b/chromium/ui/views/window/frame_caption_button.cc
new file mode 100644
index 00000000000..49026c946d7
--- /dev/null
+++ b/chromium/ui/views/window/frame_caption_button.cc
@@ -0,0 +1,297 @@
+// 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/window/frame_caption_button.h"
+
+#include "ui/base/hit_test.h"
+#include "ui/gfx/animation/slide_animation.h"
+#include "ui/gfx/animation/throb_animation.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/paint_vector_icon.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/animation/ink_drop_mask.h"
+#include "ui/views/animation/ink_drop_ripple.h"
+#include "ui/views/window/caption_button_layout_constants.h"
+#include "ui/views/window/hit_test_utils.h"
+
+namespace views {
+
+namespace {
+
+// Ink drop parameters.
+constexpr float kInkDropVisibleOpacity = 0.06f;
+
+// The duration of the crossfade animation when swapping the button's images.
+const int kSwapImagesAnimationDurationMs = 200;
+
+// The duration of the fade out animation of the old icon during a crossfade
+// animation as a ratio of |kSwapImagesAnimationDurationMs|.
+const float kFadeOutRatio = 0.5f;
+
+// The ratio applied to the button's alpha when the button is disabled.
+const float kDisabledButtonAlphaRatio = 0.5f;
+
+} // namespace
+
+// static
+const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton";
+
+FrameCaptionButton::FrameCaptionButton(views::ButtonListener* listener,
+ CaptionButtonIcon icon,
+ int hit_test_type)
+ : Button(listener),
+ icon_(icon),
+ background_color_(SK_ColorWHITE),
+ paint_as_active_(false),
+ alpha_(255),
+ ink_drop_corner_radius_(kCaptionButtonInkDropDefaultCornerRadius),
+ swap_images_animation_(new gfx::SlideAnimation(this)) {
+ views::SetHitTestComponent(this, hit_test_type);
+
+ set_animate_on_state_change(true);
+ swap_images_animation_->Reset(1);
+
+ set_has_ink_drop_action_on_click(true);
+ SetInkDropMode(InkDropMode::ON);
+ set_ink_drop_visible_opacity(kInkDropVisibleOpacity);
+ UpdateInkDropBaseColor();
+
+ // Do not flip the gfx::Canvas passed to the OnPaint() method. The snap left
+ // and snap right button icons should not be flipped. The other icons are
+ // horizontally symmetrical.
+}
+
+FrameCaptionButton::~FrameCaptionButton() = default;
+
+// static
+SkColor FrameCaptionButton::GetButtonColor(SkColor background_color) {
+ // Use IsDark() to change target colors instead of PickContrastingColor(), so
+ // that DefaultFrameHeader::GetTitleColor() (which uses different target
+ // colors) can change between light/dark targets at the same time. It looks
+ // bad when the title and caption buttons disagree about whether to be light
+ // or dark.
+ const SkColor source = color_utils::IsDark(background_color)
+ ? gfx::kGoogleGrey200
+ : gfx::kGoogleGrey700;
+ const SkColor target = color_utils::GetColorWithMaxContrast(background_color);
+ // Guarantee the caption buttons reach at least contrast ratio 3; this ratio
+ // matches that used for focus indicators, large text, and other "have to see
+ // it but perhaps don't have to read fine detail" cases.
+ const SkAlpha alpha = color_utils::GetBlendValueWithMinimumContrast(
+ source, target, background_color, 3.0f);
+ return color_utils::AlphaBlend(target, source, alpha);
+}
+
+// static
+float FrameCaptionButton::GetInactiveButtonColorAlphaRatio() {
+ return 0.38f;
+}
+
+void FrameCaptionButton::SetImage(CaptionButtonIcon icon,
+ Animate animate,
+ const gfx::VectorIcon& icon_definition) {
+ gfx::ImageSkia new_icon_image =
+ gfx::CreateVectorIcon(icon_definition, GetButtonColor(background_color_));
+
+ // The early return is dependent on |animate| because callers use SetImage()
+ // with ANIMATE_NO to progress the crossfade animation to the end.
+ if (icon == icon_ &&
+ (animate == ANIMATE_YES || !swap_images_animation_->is_animating()) &&
+ new_icon_image.BackedBySameObjectAs(icon_image_)) {
+ return;
+ }
+
+ if (animate == ANIMATE_YES)
+ crossfade_icon_image_ = icon_image_;
+
+ icon_ = icon;
+ icon_definition_ = &icon_definition;
+ icon_image_ = new_icon_image;
+
+ if (animate == ANIMATE_YES) {
+ swap_images_animation_->Reset(0);
+ swap_images_animation_->SetSlideDuration(kSwapImagesAnimationDurationMs);
+ swap_images_animation_->Show();
+ } else {
+ swap_images_animation_->Reset(1);
+ }
+
+ SchedulePaint();
+}
+
+bool FrameCaptionButton::IsAnimatingImageSwap() const {
+ return swap_images_animation_->is_animating();
+}
+
+void FrameCaptionButton::SetAlpha(int alpha) {
+ if (alpha_ != alpha) {
+ alpha_ = alpha;
+ SchedulePaint();
+ }
+}
+
+const char* FrameCaptionButton::GetClassName() const {
+ return kViewClassName;
+}
+
+void FrameCaptionButton::OnGestureEvent(ui::GestureEvent* event) {
+ // Button does not become pressed when the user drags off and then back
+ // onto the button. Make FrameCaptionButton pressed in this case because this
+ // behavior is more consistent with AlternateFrameSizeButton.
+ if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN ||
+ event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
+ if (HitTestPoint(event->location())) {
+ SetState(STATE_PRESSED);
+ RequestFocus();
+ event->StopPropagation();
+ } else {
+ SetState(STATE_NORMAL);
+ }
+ } else if (event->type() == ui::ET_GESTURE_SCROLL_END) {
+ if (HitTestPoint(event->location())) {
+ SetState(STATE_HOVERED);
+ NotifyClick(*event);
+ event->StopPropagation();
+ }
+ }
+ Button::OnGestureEvent(event);
+}
+
+views::PaintInfo::ScaleType FrameCaptionButton::GetPaintScaleType() const {
+ return views::PaintInfo::ScaleType::kUniformScaling;
+}
+
+std::unique_ptr<views::InkDrop> FrameCaptionButton::CreateInkDrop() {
+ auto ink_drop = std::make_unique<views::InkDropImpl>(this, size());
+ ink_drop->SetAutoHighlightMode(views::InkDropImpl::AutoHighlightMode::NONE);
+ ink_drop->SetShowHighlightOnHover(false);
+ return ink_drop;
+}
+
+std::unique_ptr<views::InkDropRipple> FrameCaptionButton::CreateInkDropRipple()
+ const {
+ return std::make_unique<views::FloodFillInkDropRipple>(
+ size(), GetInkdropInsets(size()), GetInkDropCenterBasedOnLastEvent(),
+ GetInkDropBaseColor(), ink_drop_visible_opacity());
+}
+
+std::unique_ptr<views::InkDropMask> FrameCaptionButton::CreateInkDropMask()
+ const {
+ return std::make_unique<views::RoundRectInkDropMask>(
+ size(), GetInkdropInsets(size()), ink_drop_corner_radius_);
+}
+
+void FrameCaptionButton::SetBackgroundColor(SkColor background_color) {
+ if (background_color_ == background_color)
+ return;
+
+ background_color_ = background_color;
+ // Refresh the icon since the color may have changed.
+ if (icon_definition_)
+ SetImage(icon_, ANIMATE_NO, *icon_definition_);
+ UpdateInkDropBaseColor();
+}
+
+void FrameCaptionButton::PaintButtonContents(gfx::Canvas* canvas) {
+ constexpr SkAlpha kHighlightVisibleOpacity = 0x14;
+ SkAlpha highlight_alpha = SK_AlphaTRANSPARENT;
+ if (hover_animation().is_animating()) {
+ highlight_alpha = hover_animation().CurrentValueBetween(
+ SK_AlphaTRANSPARENT, kHighlightVisibleOpacity);
+ } else if (state() == STATE_HOVERED || state() == STATE_PRESSED) {
+ // Painting a circular highlight in both "hovered" and "pressed" states
+ // simulates and ink drop highlight mode of
+ // AutoHighlightMode::SHOW_ON_RIPPLE.
+ highlight_alpha = kHighlightVisibleOpacity;
+ }
+
+ if (highlight_alpha != SK_AlphaTRANSPARENT) {
+ // We paint the highlight manually here rather than relying on the ink drop
+ // highlight as it doesn't work well when the button size is changing while
+ // the window is moving as a result of the animation from normal to
+ // maximized state or vice versa. https://crbug.com/840901.
+ cc::PaintFlags flags;
+ flags.setColor(GetInkDropBaseColor());
+ flags.setAlpha(highlight_alpha);
+ const gfx::Point center(GetMirroredRect(GetContentsBounds()).CenterPoint());
+ canvas->DrawCircle(center, ink_drop_corner_radius_, flags);
+ }
+
+ int icon_alpha = swap_images_animation_->CurrentValueBetween(0, 255);
+ int crossfade_icon_alpha = 0;
+ if (icon_alpha < static_cast<int>(kFadeOutRatio * 255))
+ crossfade_icon_alpha = static_cast<int>(255 - icon_alpha / kFadeOutRatio);
+
+ int centered_origin_x = (width() - icon_image_.width()) / 2;
+ int centered_origin_y = (height() - icon_image_.height()) / 2;
+
+ if (crossfade_icon_alpha > 0 && !crossfade_icon_image_.isNull()) {
+ canvas->SaveLayerAlpha(GetAlphaForIcon(alpha_));
+ cc::PaintFlags flags;
+ flags.setAlpha(icon_alpha);
+ canvas->DrawImageInt(icon_image_, centered_origin_x, centered_origin_y,
+ flags);
+
+ flags.setAlpha(crossfade_icon_alpha);
+ flags.setBlendMode(SkBlendMode::kPlus);
+ canvas->DrawImageInt(crossfade_icon_image_, centered_origin_x,
+ centered_origin_y, flags);
+ canvas->Restore();
+ } else {
+ if (!swap_images_animation_->is_animating())
+ icon_alpha = alpha_;
+ cc::PaintFlags flags;
+ flags.setAlpha(GetAlphaForIcon(icon_alpha));
+ canvas->DrawImageInt(icon_image_, centered_origin_x, centered_origin_y,
+ flags);
+ }
+}
+
+int FrameCaptionButton::GetAlphaForIcon(int base_alpha) const {
+ if (!enabled())
+ return base_alpha * kDisabledButtonAlphaRatio;
+
+ if (paint_as_active_)
+ return base_alpha;
+
+ // Paint icons as active when they are hovered over or pressed.
+ double inactive_alpha = GetInactiveButtonColorAlphaRatio();
+
+ if (hover_animation().is_animating()) {
+ inactive_alpha =
+ hover_animation().CurrentValueBetween(inactive_alpha, 1.0f);
+ } else if (state() == STATE_PRESSED || state() == STATE_HOVERED) {
+ inactive_alpha = 1.0f;
+ }
+ return base_alpha * inactive_alpha;
+}
+
+gfx::Insets FrameCaptionButton::GetInkdropInsets(
+ const gfx::Size& button_size) const {
+ const gfx::Size kInkDropHighlightSize{2 * ink_drop_corner_radius_,
+ 2 * ink_drop_corner_radius_};
+ return gfx::Insets(
+ (button_size.height() - kInkDropHighlightSize.height()) / 2,
+ (button_size.width() - kInkDropHighlightSize.width()) / 2);
+}
+
+void FrameCaptionButton::UpdateInkDropBaseColor() {
+ using color_utils::GetColorWithMaxContrast;
+ // A typical implementation would simply do
+ // GetColorWithMaxContrast(background_color_). However, this could look odd
+ // if we use a light button glyph and dark ink drop or vice versa. So
+ // instead, use the lightest/darkest color in the same direction as the button
+ // glyph color.
+ // TODO(pkasting): It would likely be better to make the button glyph always
+ // be an alpha-blended version of GetColorWithMaxContrast(background_color_).
+ const SkColor button_color = GetButtonColor(background_color_);
+ set_ink_drop_base_color(
+ GetColorWithMaxContrast(GetColorWithMaxContrast(button_color)));
+}
+
+} // namespace views
diff --git a/chromium/ui/views/window/frame_caption_button.h b/chromium/ui/views/window/frame_caption_button.h
new file mode 100644
index 00000000000..5c9cb22478d
--- /dev/null
+++ b/chromium/ui/views/window/frame_caption_button.h
@@ -0,0 +1,133 @@
+// 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_WINDOW_FRAME_CAPTION_BUTTON_H_
+#define UI_VIEWS_WINDOW_FRAME_CAPTION_BUTTON_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/views_export.h"
+#include "ui/views/window/caption_button_types.h"
+
+namespace gfx {
+class SlideAnimation;
+struct VectorIcon;
+} // namespace gfx
+
+namespace views {
+
+// Base class for the window caption buttons (minimize, maximize, restore,
+// close).
+class VIEWS_EXPORT FrameCaptionButton : public views::Button {
+ public:
+ enum Animate { ANIMATE_YES, ANIMATE_NO };
+
+ static const char kViewClassName[];
+
+ FrameCaptionButton(views::ButtonListener* listener,
+ CaptionButtonIcon icon,
+ int hit_test_type);
+ ~FrameCaptionButton() override;
+
+ // Gets the color to use for a frame caption button.
+ static SkColor GetButtonColor(SkColor background_color);
+
+ // Gets the alpha ratio for the colors of inactive frame caption buttons.
+ static float GetInactiveButtonColorAlphaRatio();
+
+ // Sets the image to use to paint the button. If |animate| is ANIMATE_YES,
+ // the button crossfades to the new visuals. If the image matches the one
+ // currently used by the button and |animate| is ANIMATE_NO, the crossfade
+ // animation is progressed to the end.
+ void SetImage(CaptionButtonIcon icon,
+ Animate animate,
+ const gfx::VectorIcon& icon_image);
+
+ // Returns true if the button is crossfading to new visuals set in
+ // SetImage().
+ bool IsAnimatingImageSwap() const;
+
+ // Sets the alpha to use for painting. Used to animate visibility changes.
+ void SetAlpha(int alpha);
+
+ // views::Button:
+ const char* GetClassName() const override;
+ void OnGestureEvent(ui::GestureEvent* event) override;
+ views::PaintInfo::ScaleType GetPaintScaleType() const override;
+ std::unique_ptr<views::InkDrop> CreateInkDrop() override;
+ std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
+ std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
+
+ void SetBackgroundColor(SkColor background_color);
+
+ void set_paint_as_active(bool paint_as_active) {
+ paint_as_active_ = paint_as_active;
+ }
+
+ bool paint_as_active() const { return paint_as_active_; }
+
+ void set_ink_drop_corner_radius(int ink_drop_corner_radius) {
+ ink_drop_corner_radius_ = ink_drop_corner_radius;
+ }
+
+ CaptionButtonIcon icon() const { return icon_; }
+
+ const gfx::ImageSkia& icon_image() const { return icon_image_; }
+
+ const gfx::VectorIcon* icon_definition_for_test() const {
+ return icon_definition_;
+ }
+
+ protected:
+ // views::Button override:
+ void PaintButtonContents(gfx::Canvas* canvas) override;
+
+ private:
+ // Determines what alpha to use for the icon based on animation and
+ // active state.
+ int GetAlphaForIcon(int base_alpha) const;
+
+ // Returns the amount by which the inkdrop ripple and mask should be insetted
+ // from the button size in order to achieve a circular inkdrop with a size
+ // equals to kInkDropHighlightSize.
+ gfx::Insets GetInkdropInsets(const gfx::Size& button_size) const;
+
+ void UpdateInkDropBaseColor();
+
+ // The button's current icon.
+ CaptionButtonIcon icon_;
+
+ // The current background color.
+ SkColor background_color_;
+
+ // Whether the button should be painted as active.
+ bool paint_as_active_;
+
+ // Current alpha to use for painting.
+ int alpha_;
+
+ // Radius of the ink drop highlight and mask.
+ int ink_drop_corner_radius_;
+
+ // The image id (kept for the purposes of testing) and image used to paint the
+ // button's icon.
+ const gfx::VectorIcon* icon_definition_ = nullptr;
+ gfx::ImageSkia icon_image_;
+
+ // The icon image to crossfade from.
+ gfx::ImageSkia crossfade_icon_image_;
+
+ // Crossfade animation started when the button's images are changed by
+ // SetImage().
+ std::unique_ptr<gfx::SlideAnimation> swap_images_animation_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameCaptionButton);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_FRAME_CAPTION_BUTTON_H_
diff --git a/chromium/ui/views/window/frame_caption_button_unittest.cc b/chromium/ui/views/window/frame_caption_button_unittest.cc
new file mode 100644
index 00000000000..211c4b883c1
--- /dev/null
+++ b/chromium/ui/views/window/frame_caption_button_unittest.cc
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/window/frame_caption_button.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/color_utils.h"
+
+namespace {
+
+constexpr SkColor kBackgroundColors[] = {
+ SK_ColorBLACK, SK_ColorDKGRAY,
+ SK_ColorGRAY, SK_ColorLTGRAY,
+ SK_ColorWHITE, SK_ColorRED,
+ SK_ColorYELLOW, SK_ColorCYAN,
+ SK_ColorBLUE, SkColorSetRGB(230, 138, 90),
+};
+
+} // namespace
+
+TEST(FrameCaptionButtonTest, ThemedColorContrast) {
+ for (SkColor background_color : kBackgroundColors) {
+ SkColor button_color =
+ views::FrameCaptionButton::GetButtonColor(background_color);
+ EXPECT_GE(color_utils::GetContrastRatio(button_color, background_color), 3);
+ }
+}
diff --git a/chromium/ui/views/window/native_frame_view.cc b/chromium/ui/views/window/native_frame_view.cc
index c25d3e9a41f..2f7c439597e 100644
--- a/chromium/ui/views/window/native_frame_view.cc
+++ b/chromium/ui/views/window/native_frame_view.cc
@@ -55,7 +55,7 @@ int NativeFrameView::NonClientHitTest(const gfx::Point& point) {
}
void NativeFrameView::GetWindowMask(const gfx::Size& size,
- gfx::Path* window_mask) {
+ SkPath* window_mask) {
// Nothing to do, we use the default window mask.
}
diff --git a/chromium/ui/views/window/native_frame_view.h b/chromium/ui/views/window/native_frame_view.h
index 16045930327..93066f31e1e 100644
--- a/chromium/ui/views/window/native_frame_view.h
+++ b/chromium/ui/views/window/native_frame_view.h
@@ -24,7 +24,7 @@ class VIEWS_EXPORT NativeFrameView : public NonClientFrameView {
gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const override;
int NonClientHitTest(const gfx::Point& point) override;
- void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override;
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override;
void ResetWindowControls() override;
void UpdateWindowIcon() override;
void UpdateWindowTitle() override;
diff --git a/chromium/ui/views/window/non_client_view.cc b/chromium/ui/views/window/non_client_view.cc
index eb874a063a8..0f637b09dac 100644
--- a/chromium/ui/views/window/non_client_view.cc
+++ b/chromium/ui/views/window/non_client_view.cc
@@ -34,7 +34,7 @@ static const int kClientViewIndex = 1;
// NonClientFrameView, default implementations:
bool NonClientFrameView::GetClientMask(const gfx::Size& size,
- gfx::Path* mask) const {
+ SkPath* mask) const {
return false;
}
@@ -102,8 +102,7 @@ int NonClientView::NonClientHitTest(const gfx::Point& point) {
return frame_view_->NonClientHitTest(point);
}
-void NonClientView::GetWindowMask(const gfx::Size& size,
- gfx::Path* window_mask) {
+void NonClientView::GetWindowMask(const gfx::Size& size, SkPath* window_mask) {
frame_view_->GetWindowMask(size, window_mask);
}
@@ -172,7 +171,7 @@ void NonClientView::Layout() {
client_view_->Layout();
}
- gfx::Path client_clip;
+ SkPath client_clip;
if (frame_view_->GetClientMask(client_view_->size(), &client_clip))
client_view_->set_clip_path(client_clip);
@@ -319,6 +318,10 @@ const char* NonClientFrameView::GetClassName() const {
return kViewClassName;
}
+void NonClientFrameView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ SchedulePaint();
+}
+
////////////////////////////////////////////////////////////////////////////////
// NonClientFrameView, protected:
diff --git a/chromium/ui/views/window/non_client_view.h b/chromium/ui/views/window/non_client_view.h
index 8a11a2790bd..17f5d9faa1d 100644
--- a/chromium/ui/views/window/non_client_view.h
+++ b/chromium/ui/views/window/non_client_view.h
@@ -9,10 +9,6 @@
#include "ui/views/view.h"
#include "ui/views/view_targeter_delegate.h"
-namespace gfx {
-class Path;
-}
-
namespace views {
class ClientView;
@@ -68,8 +64,7 @@ class VIEWS_EXPORT NonClientFrameView : public View,
// Gets the clip mask (in this View's parent's coordinates) that should be
// applied to the client view. Returns false if no special clip should be
// used.
- virtual bool GetClientMask(const gfx::Size& size,
- gfx::Path* mask) const;
+ virtual bool GetClientMask(const gfx::Size& size, SkPath* mask) const;
// This function must ask the ClientView to do a hittest. We don't do this in
// the parent NonClientView because that makes it more difficult to calculate
@@ -81,8 +76,7 @@ class VIEWS_EXPORT NonClientFrameView : public View,
// Used to make the hosting widget shaped (non-rectangular). For a
// rectangular window do nothing. For a shaped window update |window_mask|
// accordingly. |size| is the size of the widget.
- virtual void GetWindowMask(const gfx::Size& size,
- gfx::Path* window_mask) = 0;
+ virtual void GetWindowMask(const gfx::Size& size, SkPath* window_mask) = 0;
virtual void ResetWindowControls() = 0;
virtual void UpdateWindowIcon() = 0;
virtual void UpdateWindowTitle() = 0;
@@ -96,6 +90,7 @@ class VIEWS_EXPORT NonClientFrameView : public View,
// View:
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
const char* GetClassName() const override;
+ void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
protected:
NonClientFrameView();
@@ -192,7 +187,7 @@ class VIEWS_EXPORT NonClientView : public View, public ViewTargeterDelegate {
// Returns a mask to be used to clip the top level window for the given
// size. This is used to create the non-rectangular window shape.
- void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask);
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask);
// Tells the window controls as rendered by the NonClientView to reset
// themselves to a normal state. This happens in situations where the
diff --git a/chromium/ui/views/window/vector_icons/BUILD.gn b/chromium/ui/views/window/vector_icons/BUILD.gn
new file mode 100644
index 00000000000..d17416574de
--- /dev/null
+++ b/chromium/ui/views/window/vector_icons/BUILD.gn
@@ -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.
+
+import("//components/vector_icons/vector_icons.gni")
+
+aggregate_vector_icons("window_control_vector_icons") {
+ icon_directory = "."
+
+ icons = [
+ "window_control_close.icon",
+ "window_control_maximize.icon",
+ "window_control_minimize.icon",
+ "window_control_restore.icon",
+ ]
+}
+
+source_set("vector_icons") {
+ sources = get_target_outputs(":window_control_vector_icons")
+
+ deps = [
+ ":window_control_vector_icons",
+ "//base",
+ "//skia",
+ "//ui/gfx",
+ ]
+}
diff --git a/chromium/ui/views/window/vector_icons/vector_icons.cc.template b/chromium/ui/views/window/vector_icons/vector_icons.cc.template
new file mode 100644
index 00000000000..7dd39390e0c
--- /dev/null
+++ b/chromium/ui/views/window/vector_icons/vector_icons.cc.template
@@ -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.
+
+// vector_icons.cc.template is used to generate vector_icons.cc. Edit the former
+// rather than the latter.
+
+#include "ui/views/window/vector_icons/vector_icons.h"
+
+#include "base/logging.h"
+#include "components/vector_icons/cc_macros.h"
+#include "ui/gfx/vector_icon_types.h"
+
+namespace views {
+
+using namespace gfx;
+
+TEMPLATE_PLACEHOLDER
+
+} // namespace views
diff --git a/chromium/ui/views/window/vector_icons/vector_icons.h.template b/chromium/ui/views/window/vector_icons/vector_icons.h.template
new file mode 100644
index 00000000000..6d77e7257c8
--- /dev/null
+++ b/chromium/ui/views/window/vector_icons/vector_icons.h.template
@@ -0,0 +1,26 @@
+// 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.
+
+// vector_icons.h.template is used to generate vector_icons.h. Edit the former
+// rather than the latter.
+
+#ifndef UI_VIEWS_WINDOW_VECTOR_ICONS_VECTOR_ICONS_H_
+#define UI_VIEWS_WINDOW_VECTOR_ICONS_VECTOR_ICONS_H_
+
+namespace gfx {
+struct VectorIcon;
+}
+
+#define VECTOR_ICON_TEMPLATE_H(icon_name) \
+extern const gfx::VectorIcon icon_name;
+
+namespace views {
+
+TEMPLATE_PLACEHOLDER
+
+} // namespace views
+
+#undef VECTOR_ICON_TEMPLATE_H
+
+#endif // UI_VIEWS_WINDOW_VECTOR_ICONS_VECTOR_ICONS_H_
diff --git a/chromium/ui/views/window/vector_icons/window_control_close.icon b/chromium/ui/views/window/vector_icons/window_control_close.icon
new file mode 100644
index 00000000000..704ebd94223
--- /dev/null
+++ b/chromium/ui/views/window/vector_icons/window_control_close.icon
@@ -0,0 +1,35 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 23, 3.22f,
+LINE_TO, 20.78f, 1,
+LINE_TO, 12, 9.78f,
+LINE_TO, 3.22f, 1,
+LINE_TO, 1, 3.22f,
+LINE_TO, 9.78f, 12,
+LINE_TO, 1, 20.78f,
+LINE_TO, 3.22f, 23,
+LINE_TO, 12, 14.22f,
+LINE_TO, 20.78f, 23,
+LINE_TO, 23, 20.78f,
+LINE_TO, 14.22f, 12,
+LINE_TO, 23, 3.22f,
+CLOSE
+
+CANVAS_DIMENSIONS, 12,
+MOVE_TO, 6, 4.59f,
+LINE_TO, 2.46f, 1.05f,
+LINE_TO, 1.05f, 2.46f,
+LINE_TO, 4.59f, 6,
+LINE_TO, 1.05f, 9.54f,
+R_LINE_TO, 1.41f, 1.41f,
+LINE_TO, 6, 7.41f,
+R_LINE_TO, 3.54f, 3.54f,
+R_LINE_TO, 1.41f, -1.41f,
+LINE_TO, 7.41f, 6,
+R_LINE_TO, 3.54f, -3.54f,
+LINE_TO, 9.54f, 1.05f,
+LINE_TO, 6, 4.59f,
+CLOSE
diff --git a/chromium/ui/views/window/vector_icons/window_control_maximize.icon b/chromium/ui/views/window/vector_icons/window_control_maximize.icon
new file mode 100644
index 00000000000..2cabda265bd
--- /dev/null
+++ b/chromium/ui/views/window/vector_icons/window_control_maximize.icon
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 23, 1,
+R_V_LINE_TO, 22,
+H_LINE_TO, 1,
+V_LINE_TO, 1,
+R_H_LINE_TO, 22,
+CLOSE,
+R_MOVE_TO, -3, 19,
+H_LINE_TO, 4,
+V_LINE_TO, 4,
+R_H_LINE_TO, 16,
+R_V_LINE_TO, 16,
+CLOSE
+
+CANVAS_DIMENSIONS, 12,
+MOVE_TO, 11, 1,
+R_V_LINE_TO, 10,
+H_LINE_TO, 1,
+V_LINE_TO, 1,
+R_H_LINE_TO, 10,
+CLOSE,
+MOVE_TO, 9, 9,
+H_LINE_TO, 3,
+V_LINE_TO, 3,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6,
+CLOSE
diff --git a/chromium/ui/views/window/vector_icons/window_control_minimize.icon b/chromium/ui/views/window/vector_icons/window_control_minimize.icon
new file mode 100644
index 00000000000..c15e84b2a8a
--- /dev/null
+++ b/chromium/ui/views/window/vector_icons/window_control_minimize.icon
@@ -0,0 +1,17 @@
+// 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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 1, 20,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 3,
+H_LINE_TO, 1,
+CLOSE
+
+CANVAS_DIMENSIONS, 12,
+MOVE_TO, 1, 9,
+R_H_LINE_TO, 10,
+R_V_LINE_TO, 2,
+H_LINE_TO, 1,
+CLOSE
diff --git a/chromium/ui/views/window/vector_icons/window_control_restore.icon b/chromium/ui/views/window/vector_icons/window_control_restore.icon
new file mode 100644
index 00000000000..f01da8f6d33
--- /dev/null
+++ b/chromium/ui/views/window/vector_icons/window_control_restore.icon
@@ -0,0 +1,47 @@
+// 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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 23, 16,
+H_LINE_TO, 8,
+V_LINE_TO, 1,
+R_H_LINE_TO, 15,
+R_V_LINE_TO, 15,
+CLOSE,
+R_MOVE_TO, -12, -3,
+V_LINE_TO, 4,
+R_H_LINE_TO, 9,
+R_V_LINE_TO, 9,
+R_H_LINE_TO, -9,
+CLOSE,
+MOVE_TO, 4, 8,
+H_LINE_TO, 1,
+R_V_LINE_TO, 15,
+R_H_LINE_TO, 15,
+R_V_LINE_TO, -3,
+H_LINE_TO, 4,
+V_LINE_TO, 8,
+CLOSE
+
+CANVAS_DIMENSIONS, 12,
+MOVE_TO, 11, 8,
+H_LINE_TO, 4,
+V_LINE_TO, 1,
+R_H_LINE_TO, 7,
+R_V_LINE_TO, 7,
+CLOSE,
+MOVE_TO, 6, 6,
+V_LINE_TO, 3,
+R_H_LINE_TO, 3,
+R_V_LINE_TO, 3,
+H_LINE_TO, 6,
+CLOSE,
+MOVE_TO, 3, 3,
+H_LINE_TO, 1,
+R_V_LINE_TO, 8,
+R_H_LINE_TO, 8,
+V_LINE_TO, 9,
+H_LINE_TO, 3,
+V_LINE_TO, 3,
+CLOSE
diff --git a/chromium/ui/views/window/window_shape.cc b/chromium/ui/views/window/window_shape.cc
index ab9868e51b3..e271aebe66a 100644
--- a/chromium/ui/views/window/window_shape.cc
+++ b/chromium/ui/views/window/window_shape.cc
@@ -4,13 +4,14 @@
#include "ui/views/window/window_shape.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/path.h"
namespace views {
-void GetDefaultWindowMask(const gfx::Size& size, float scale,
- gfx::Path* window_mask) {
+void GetDefaultWindowMask(const gfx::Size& size,
+ float scale,
+ SkPath* window_mask) {
const SkScalar sk_scale = SkFloatToScalar(scale);
const SkScalar width = SkIntToScalar(size.width()) / sk_scale;
const SkScalar height = SkIntToScalar(size.height()) / sk_scale;
diff --git a/chromium/ui/views/window/window_shape.h b/chromium/ui/views/window/window_shape.h
index 6e288e4f01d..8e4d54f66d2 100644
--- a/chromium/ui/views/window/window_shape.h
+++ b/chromium/ui/views/window/window_shape.h
@@ -7,9 +7,10 @@
#include "ui/views/views_export.h"
+class SkPath;
+
namespace gfx {
class Size;
-class Path;
}
namespace views {
@@ -18,7 +19,7 @@ namespace views {
// ui/resources/window_*
VIEWS_EXPORT void GetDefaultWindowMask(const gfx::Size& size,
float scale,
- gfx::Path* window_mask);
+ SkPath* window_mask);
} // namespace views
diff --git a/chromium/ui/views_bridge_mac/BUILD.gn b/chromium/ui/views_bridge_mac/BUILD.gn
index 1043a8aa7bb..d4111ab76f5 100644
--- a/chromium/ui/views_bridge_mac/BUILD.gn
+++ b/chromium/ui/views_bridge_mac/BUILD.gn
@@ -4,10 +4,20 @@
import("//mojo/public/tools/bindings/mojom.gni")
+config("views_bridge_mac_warnings") {
+ if (is_mac) {
+ # TODO(thakis): Remove this once http://crbug.com/383820 is figured out
+ cflags = [ "-Wno-nonnull" ]
+ }
+}
+
component("views_bridge_mac") {
assert(is_mac)
+ configs += [ ":views_bridge_mac_warnings" ]
sources = [
+ "alert.h",
+ "alert.mm",
"bridged_native_widget_host_helper.h",
"cocoa_mouse_capture.h",
"cocoa_mouse_capture.mm",
@@ -17,7 +27,11 @@ component("views_bridge_mac") {
]
defines = [ "VIEWS_BRIDGE_MAC_IMPLEMENTATION" ]
deps = [
+ ":mojo",
"//base",
+ "//base:i18n",
+ "//mojo/public/cpp/bindings",
+ "//ui/accelerated_widget_mac",
"//ui/base",
"//ui/events",
"//ui/gfx",
@@ -29,17 +43,21 @@ mojom("mojo") {
assert(is_mac)
sources = [
+ "mojo/alert.mojom",
"mojo/bridge_factory.mojom",
"mojo/bridged_native_widget.mojom",
"mojo/bridged_native_widget_host.mojom",
+ "mojo/text_input_host.mojom",
]
public_deps = [
"//mojo/public/mojom/base",
+ "//ui/base/accelerators/mojo:interfaces",
"//ui/base/mojo",
"//ui/display/mojo:interfaces",
"//ui/events/mojo:interfaces",
"//ui/gfx/geometry/mojo",
"//ui/gfx/mojo",
+ "//ui/gfx/range/mojo",
]
}
diff --git a/chromium/ui/views_bridge_mac/alert.h b/chromium/ui/views_bridge_mac/alert.h
new file mode 100644
index 00000000000..3a38554350e
--- /dev/null
+++ b/chromium/ui/views_bridge_mac/alert.h
@@ -0,0 +1,65 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_BRIDGE_MAC_ALERT_H_
+#define UI_VIEWS_BRIDGE_MAC_ALERT_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "ui/gfx/text_elider.h"
+#include "ui/views_bridge_mac/mojo/alert.mojom.h"
+#include "ui/views_bridge_mac/views_bridge_mac_export.h"
+
+@class AlertBridgeHelper;
+
+namespace views_bridge_mac {
+
+// Class that displays an NSAlert with associated UI as described by the mojo
+// AlertBridge interface.
+class VIEWS_BRIDGE_MAC_EXPORT AlertBridge
+ : public views_bridge_mac::mojom::AlertBridge {
+ public:
+ // Creates a new alert which controls its own lifetime. It will destroy itself
+ // once its NSAlert goes away.
+ AlertBridge(mojom::AlertBridgeRequest bridge_request);
+
+ // Send the specified disposition via the Show callback, then destroy |this|.
+ void SendResultAndDestroy(mojom::AlertDisposition disposition);
+
+ // Called by Cocoa to indicate when the NSAlert is visible (and can be
+ // programmatically updated by Accept, Cancel, and Close).
+ void SetAlertHasShown();
+
+ private:
+ // Private destructor is called only through SendResultAndDestroy.
+ ~AlertBridge() override;
+
+ // Handle being disconnected (e.g, because the alert was programmatically
+ // dismissed).
+ void OnConnectionError();
+
+ // views_bridge_mac::mojom::Alert:
+ void Show(mojom::AlertBridgeInitParamsPtr params,
+ ShowCallback callback) override;
+
+ // The NSAlert's owner and delegate.
+ base::scoped_nsobject<AlertBridgeHelper> helper_;
+
+ // Set once the alert window is showing (needed because showing is done in a
+ // posted task).
+ bool alert_shown_ = false;
+
+ // The callback to make when the dialog has finished running.
+ ShowCallback callback_;
+
+ mojo::Binding<views_bridge_mac::mojom::AlertBridge> mojo_binding_;
+ base::WeakPtrFactory<AlertBridge> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(AlertBridge);
+};
+
+} // namespace views_bridge_mac
+
+#endif // UI_VIEWS_BRIDGE_MAC_ALERT_H_
diff --git a/chromium/ui/views_bridge_mac/alert.mm b/chromium/ui/views_bridge_mac/alert.mm
new file mode 100644
index 00000000000..4868e711b71
--- /dev/null
+++ b/chromium/ui/views_bridge_mac/alert.mm
@@ -0,0 +1,318 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views_bridge_mac/alert.h"
+
+#include "base/i18n/rtl.h"
+#import "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+using views_bridge_mac::mojom::AlertBridgeInitParams;
+using views_bridge_mac::mojom::AlertDisposition;
+
+namespace {
+
+const int kSlotsPerLine = 50;
+const int kMessageTextMaxSlots = 2000;
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// AlertBridgeHelper:
+
+// Helper object that receives the notification that the dialog/sheet is
+// going away. Is responsible for cleaning itself up.
+@interface AlertBridgeHelper : NSObject <NSAlertDelegate> {
+ @private
+ base::scoped_nsobject<NSAlert> alert_;
+ views_bridge_mac::AlertBridge* alertBridge_; // Weak.
+ base::scoped_nsobject<NSTextField> textField_;
+}
+@property(assign, nonatomic) views_bridge_mac::AlertBridge* alertBridge;
+
+// Returns the underlying alert.
+- (NSAlert*)alert;
+
+// Set a blank icon for dialogs with text provided by the page.
+- (void)setBlankIcon;
+
+// Add a text field to the alert.
+- (void)addTextFieldWithPrompt:(NSString*)prompt;
+
+// Presents an AppKit blocking dialog.
+- (void)showAlert;
+@end
+
+@implementation AlertBridgeHelper
+@synthesize alertBridge = alertBridge_;
+
+- (void)initAlert:(AlertBridgeInitParams*)params {
+ alert_.reset([[NSAlert alloc] init]);
+ [alert_ setDelegate:self];
+
+ if (params->hide_application_icon)
+ [self setBlankIcon];
+ if (params->text_field_text) {
+ [self addTextFieldWithPrompt:base::SysUTF16ToNSString(
+ *params->text_field_text)];
+ }
+ NSString* informative_text = base::SysUTF16ToNSString(params->message_text);
+
+ // Truncate long JS alerts - crbug.com/331219
+ NSCharacterSet* newline_char_set = [NSCharacterSet newlineCharacterSet];
+ for (size_t index = 0, slots_count = 0; index < informative_text.length;
+ ++index) {
+ unichar current_char = [informative_text characterAtIndex:index];
+ if ([newline_char_set characterIsMember:current_char])
+ slots_count += kSlotsPerLine;
+ else
+ slots_count++;
+ if (slots_count > kMessageTextMaxSlots) {
+ base::string16 info_text = base::SysNSStringToUTF16(informative_text);
+ informative_text = base::SysUTF16ToNSString(
+ gfx::TruncateString(info_text, index, gfx::WORD_BREAK));
+ break;
+ }
+ }
+
+ [alert_ setInformativeText:informative_text];
+ NSString* message_text = l10n_util::FixUpWindowsStyleLabel(params->title);
+ [alert_ setMessageText:message_text];
+ [alert_ addButtonWithTitle:l10n_util::FixUpWindowsStyleLabel(
+ params->primary_button_text)];
+
+ if (params->secondary_button_text) {
+ NSButton* other =
+ [alert_ addButtonWithTitle:l10n_util::FixUpWindowsStyleLabel(
+ *params->secondary_button_text)];
+ [other setKeyEquivalent:@"\e"];
+ }
+ if (params->check_box_text) {
+ [alert_ setShowsSuppressionButton:YES];
+ NSString* suppression_title =
+ l10n_util::FixUpWindowsStyleLabel(*params->check_box_text);
+ [[alert_ suppressionButton] setTitle:suppression_title];
+ }
+
+ // Fix RTL dialogs.
+ //
+ // Mac OS X will always display NSAlert strings as LTR. A workaround is to
+ // manually set the text as attributed strings in the implementing
+ // NSTextFields. This is a basic correctness issue.
+ //
+ // In addition, for readability, the overall alignment is set based on the
+ // directionality of the first strongly-directional character.
+ //
+ // If the dialog fields are selectable then they will scramble when clicked.
+ // Therefore, selectability is disabled.
+ //
+ // See http://crbug.com/70806 for more details.
+
+ bool message_has_rtl =
+ base::i18n::StringContainsStrongRTLChars(params->title);
+ bool informative_has_rtl =
+ base::i18n::StringContainsStrongRTLChars(params->message_text);
+
+ NSTextField* message_text_field = nil;
+ NSTextField* informative_text_field = nil;
+ if (message_has_rtl || informative_has_rtl) {
+ // Force layout of the dialog. NSAlert leaves its dialog alone once laid
+ // out; if this is not done then all the modifications that are to come will
+ // be un-done when the dialog is finally displayed.
+ [alert_ layout];
+
+ // Locate the NSTextFields that implement the text display. These are
+ // actually available as the ivars |_messageField| and |_informationField|
+ // of the NSAlert, but it is safer (and more forward-compatible) to search
+ // for them in the subviews.
+ for (NSView* view in [[[alert_ window] contentView] subviews]) {
+ NSTextField* text_field = base::mac::ObjCCast<NSTextField>(view);
+ if ([[text_field stringValue] isEqualTo:message_text])
+ message_text_field = text_field;
+ else if ([[text_field stringValue] isEqualTo:informative_text])
+ informative_text_field = text_field;
+ }
+
+ // This may fail in future OS releases, but it will still work for shipped
+ // versions of Chromium.
+ DCHECK(message_text_field);
+ DCHECK(informative_text_field);
+ }
+
+ if (message_has_rtl && message_text_field) {
+ base::scoped_nsobject<NSMutableParagraphStyle> alignment(
+ [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
+ [alignment setAlignment:NSRightTextAlignment];
+
+ NSDictionary* alignment_attributes =
+ @{NSParagraphStyleAttributeName : alignment};
+ base::scoped_nsobject<NSAttributedString> attr_string(
+ [[NSAttributedString alloc] initWithString:message_text
+ attributes:alignment_attributes]);
+
+ [message_text_field setAttributedStringValue:attr_string];
+ [message_text_field setSelectable:NO];
+ }
+
+ if (informative_has_rtl && informative_text_field) {
+ base::i18n::TextDirection direction =
+ base::i18n::GetFirstStrongCharacterDirection(params->message_text);
+ base::scoped_nsobject<NSMutableParagraphStyle> alignment(
+ [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
+ [alignment setAlignment:(direction == base::i18n::RIGHT_TO_LEFT)
+ ? NSRightTextAlignment
+ : NSLeftTextAlignment];
+
+ NSDictionary* alignment_attributes =
+ @{NSParagraphStyleAttributeName : alignment};
+ base::scoped_nsobject<NSAttributedString> attr_string(
+ [[NSAttributedString alloc] initWithString:informative_text
+ attributes:alignment_attributes]);
+
+ [informative_text_field setAttributedStringValue:attr_string];
+ [informative_text_field setSelectable:NO];
+ }
+}
+
+- (void)setBlankIcon {
+ NSImage* image =
+ [[[NSImage alloc] initWithSize:NSMakeSize(1, 1)] autorelease];
+ [alert_ setIcon:image];
+}
+
+- (NSAlert*)alert {
+ return alert_;
+}
+
+- (void)addTextFieldWithPrompt:(NSString*)prompt {
+ DCHECK(!textField_);
+ textField_.reset(
+ [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)]);
+ [[textField_ cell] setLineBreakMode:NSLineBreakByTruncatingTail];
+ [[self alert] setAccessoryView:textField_];
+ [[alert_ window] setInitialFirstResponder:textField_];
+
+ [textField_ setStringValue:prompt];
+}
+
+// |contextInfo| is the JavaScriptAppModalDialogCocoa that owns us.
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ switch (returnCode) {
+ case NSAlertFirstButtonReturn: // OK
+ alertBridge_->SendResultAndDestroy(AlertDisposition::PRIMARY_BUTTON);
+ break;
+ case NSAlertSecondButtonReturn: // Cancel
+ alertBridge_->SendResultAndDestroy(AlertDisposition::SECONDARY_BUTTON);
+ break;
+ case NSModalResponseStop: // Window was closed underneath us
+ alertBridge_->SendResultAndDestroy(AlertDisposition::CLOSE);
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+- (void)showAlert {
+ DCHECK(alertBridge_);
+ alertBridge_->SetAlertHasShown();
+ NSAlert* alert = [self alert];
+ [alert layout];
+ [[alert window] recalculateKeyViewLoop];
+ // TODO(crbug.com/841631): Migrate to `[NSWindow
+ // beginSheetModalForWindow:completionHandler:]` instead.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ [alert beginSheetModalForWindow:nil // nil here makes it app-modal
+ modalDelegate:self
+ didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+ contextInfo:NULL];
+#pragma clang diagnostic pop
+}
+
+- (void)closeWindow {
+ DCHECK(alertBridge_);
+ [NSApp endSheet:[[self alert] window]];
+}
+
+- (base::string16)input {
+ if (textField_)
+ return base::SysNSStringToUTF16([textField_ stringValue]);
+ return base::string16();
+}
+
+- (bool)shouldSuppress {
+ if ([[self alert] showsSuppressionButton])
+ return [[[self alert] suppressionButton] state] == NSOnState;
+ return false;
+}
+
+@end
+
+namespace views_bridge_mac {
+
+////////////////////////////////////////////////////////////////////////////////
+// AlertBridge:
+
+AlertBridge::AlertBridge(mojom::AlertBridgeRequest bridge_request)
+ : mojo_binding_(this), weak_factory_(this) {
+ mojo_binding_.Bind(std::move(bridge_request),
+ ui::WindowResizeHelperMac::Get()->task_runner());
+ mojo_binding_.set_connection_error_handler(base::BindOnce(
+ &AlertBridge::OnConnectionError, weak_factory_.GetWeakPtr()));
+}
+
+AlertBridge::~AlertBridge() {
+ [helper_ setAlertBridge:nil];
+ [NSObject cancelPreviousPerformRequestsWithTarget:helper_.get()];
+}
+
+void AlertBridge::OnConnectionError() {
+ // If the alert has been shown, then close the window, and |this| will delete
+ // itself after the window is closed. Otherwise, just delete |this|
+ // immediately.
+ if (alert_shown_)
+ [helper_ closeWindow];
+ else
+ delete this;
+}
+
+void AlertBridge::SendResultAndDestroy(AlertDisposition disposition) {
+ DCHECK(callback_);
+ std::move(callback_).Run(disposition, [helper_ input],
+ [helper_ shouldSuppress]);
+ delete this;
+}
+
+void AlertBridge::SetAlertHasShown() {
+ DCHECK(!alert_shown_);
+ alert_shown_ = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AlertBridge, mojo::AlertBridge:
+
+void AlertBridge::Show(mojom::AlertBridgeInitParamsPtr params,
+ ShowCallback callback) {
+ callback_ = std::move(callback);
+
+ // Create a helper which will receive the sheet ended selector. It will
+ // delete itself when done.
+ helper_.reset([[AlertBridgeHelper alloc] init]);
+ [helper_ setAlertBridge:this];
+ [helper_ initAlert:params.get()];
+
+ // Dispatch the method to show the alert back to the top of the CFRunLoop.
+ // This fixes an interaction bug with NSSavePanel. http://crbug.com/375785
+ // When this object is destroyed, outstanding performSelector: requests
+ // should be cancelled.
+ [helper_.get() performSelector:@selector(showAlert)
+ withObject:nil
+ afterDelay:0];
+}
+
+} // namespace views_bridge_mac
diff --git a/chromium/ui/views_bridge_mac/bridge_factory_impl.h b/chromium/ui/views_bridge_mac/bridge_factory_impl.h
index 5075e76bf52..d42be356aec 100644
--- a/chromium/ui/views_bridge_mac/bridge_factory_impl.h
+++ b/chromium/ui/views_bridge_mac/bridge_factory_impl.h
@@ -7,6 +7,7 @@
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "ui/views/views_export.h"
+#include "ui/views_bridge_mac/mojo/alert.mojom.h"
#include "ui/views_bridge_mac/mojo/bridge_factory.mojom.h"
#include "ui/views_bridge_mac/mojo/bridged_native_widget.mojom.h"
#include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
@@ -23,10 +24,12 @@ class VIEWS_EXPORT BridgeFactoryImpl : public mojom::BridgeFactory {
void BindRequest(mojom::BridgeFactoryAssociatedRequest request);
// mojom::BridgeFactory:
+ void CreateAlert(mojom::AlertBridgeRequest bridge_request) override;
void CreateBridgedNativeWidget(
uint64_t bridge_id,
mojom::BridgedNativeWidgetAssociatedRequest bridge_request,
- mojom::BridgedNativeWidgetHostAssociatedPtrInfo host) override;
+ mojom::BridgedNativeWidgetHostAssociatedPtrInfo host,
+ mojom::TextInputHostAssociatedPtrInfo text_input_host) override;
private:
friend class base::NoDestructor<BridgeFactoryImpl>;
diff --git a/chromium/ui/views_bridge_mac/bridge_factory_impl.mm b/chromium/ui/views_bridge_mac/bridge_factory_impl.mm
index d4ba3ea4de8..614379e22a8 100644
--- a/chromium/ui/views_bridge_mac/bridge_factory_impl.mm
+++ b/chromium/ui/views_bridge_mac/bridge_factory_impl.mm
@@ -7,6 +7,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/alert.h"
#include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
@@ -20,12 +21,15 @@ namespace {
class Bridge : public BridgedNativeWidgetHostHelper {
public:
Bridge(uint64_t bridge_id,
+ mojom::BridgedNativeWidgetAssociatedRequest bridge_request,
mojom::BridgedNativeWidgetHostAssociatedPtrInfo host_ptr,
- mojom::BridgedNativeWidgetAssociatedRequest bridge_request) {
+ mojom::TextInputHostAssociatedPtrInfo text_input_host_ptr) {
host_ptr_.Bind(std::move(host_ptr),
ui::WindowResizeHelperMac::Get()->task_runner());
+ text_input_host_ptr_.Bind(std::move(text_input_host_ptr),
+ ui::WindowResizeHelperMac::Get()->task_runner());
bridge_impl_ = std::make_unique<BridgedNativeWidgetImpl>(
- bridge_id, host_ptr_.get(), this);
+ bridge_id, host_ptr_.get(), this, text_input_host_ptr_.get());
bridge_impl_->BindRequest(
std::move(bridge_request),
base::BindOnce(&Bridge::OnConnectionError, base::Unretained(this)));
@@ -41,12 +45,7 @@ class Bridge : public BridgedNativeWidgetHostHelper {
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);
+ host_ptr_->GetRootViewAccessibilityToken(&browser_pid, &element_token);
[NSAccessibilityRemoteUIElement
registerRemoteUIProcessIdentifier:browser_pid];
remote_accessibility_element_ =
@@ -77,13 +76,18 @@ class Bridge : public BridgedNativeWidgetHostHelper {
gfx::Point* baseline_point) override {
*found_word = false;
}
- double SheetPositionY() override { return 0; }
views_bridge_mac::DragDropClient* GetDragDropClient() override {
// Drag-drop only doesn't work across mojo yet.
return nullptr;
}
+ ui::TextInputClient* GetTextInputClient() override {
+ // Text input doesn't work across mojo yet.
+ return nullptr;
+ }
mojom::BridgedNativeWidgetHostAssociatedPtr host_ptr_;
+ mojom::TextInputHostAssociatedPtr text_input_host_ptr_;
+
std::unique_ptr<BridgedNativeWidgetImpl> bridge_impl_;
base::scoped_nsobject<NSAccessibilityRemoteUIElement>
remote_accessibility_element_;
@@ -103,13 +107,19 @@ void BridgeFactoryImpl::BindRequest(
ui::WindowResizeHelperMac::Get()->task_runner());
}
+void BridgeFactoryImpl::CreateAlert(mojom::AlertBridgeRequest bridge_request) {
+ // The resulting object manages its own lifetime.
+ ignore_result(new AlertBridge(std::move(bridge_request)));
+}
+
void BridgeFactoryImpl::CreateBridgedNativeWidget(
uint64_t bridge_id,
mojom::BridgedNativeWidgetAssociatedRequest bridge_request,
- mojom::BridgedNativeWidgetHostAssociatedPtrInfo host) {
+ mojom::BridgedNativeWidgetHostAssociatedPtrInfo host,
+ mojom::TextInputHostAssociatedPtrInfo text_input_host) {
// The resulting object will be destroyed when its message pipe is closed.
- ignore_result(
- new Bridge(bridge_id, std::move(host), std::move(bridge_request)));
+ ignore_result(new Bridge(bridge_id, std::move(bridge_request),
+ std::move(host), std::move(text_input_host)));
}
BridgeFactoryImpl::BridgeFactoryImpl() : binding_(this) {}
diff --git a/chromium/ui/views_bridge_mac/bridged_content_view.h b/chromium/ui/views_bridge_mac/bridged_content_view.h
index b10f06bbb3b..7c096dd2cdd 100644
--- a/chromium/ui/views_bridge_mac/bridged_content_view.h
+++ b/chromium/ui/views_bridge_mac/bridged_content_view.h
@@ -32,17 +32,6 @@ VIEWS_EXPORT
// Weak, reset by clearView.
views::BridgedNativeWidgetImpl* bridge_;
- // Weak. If non-null the TextInputClient of the currently focused View in the
- // hierarchy rooted at |hostedView_|. Owned by the focused View.
- // TODO(ccameron): Remove this member.
- ui::TextInputClient* textInputClient_;
-
- // The TextInputClient about to be set. Requests for a new -inputContext will
- // use this, but while the input is changing, |self| still needs to service
- // IME requests using the old |textInputClient_|.
- // TODO(ccameron): Remove this member.
- ui::TextInputClient* pendingTextInputClient_;
-
// A tracking area installed to enable mouseMoved events.
ui::ScopedCrTrackingArea cursorTrackingArea_;
@@ -62,7 +51,6 @@ VIEWS_EXPORT
}
@property(readonly, nonatomic) views::BridgedNativeWidgetImpl* bridge;
-@property(assign, nonatomic) ui::TextInputClient* textInputClient;
@property(assign, nonatomic) BOOL drawMenuBackgroundForBlur;
// Initialize the NSView -> views::View bridge. |viewToHost| must be non-NULL.
@@ -85,6 +73,14 @@ VIEWS_EXPORT
// or not.
- (void)updateFullKeyboardAccess;
+// The TextInputClient of the currently focused views::View.
+// TODO(ccameron): This cannot be relied on across processes.
+- (ui::TextInputClient*)textInputClient;
+
+// Returns true if it is needed to call -[NSApp updateWindows] while updating
+// the text input client.
+- (bool)needsUpdateWindows;
+
@end
#endif // UI_VIEWS_BRIDGE_MAC_BRIDGED_CONTENT_VIEW_H_
diff --git a/chromium/ui/views_bridge_mac/bridged_content_view.mm b/chromium/ui/views_bridge_mac/bridged_content_view.mm
index 397425e8905..d5a2b4e67e2 100644
--- a/chromium/ui/views_bridge_mac/bridged_content_view.mm
+++ b/chromium/ui/views_bridge_mac/bridged_content_view.mm
@@ -9,6 +9,7 @@
#import "base/mac/mac_util.h"
#import "base/mac/scoped_nsobject.h"
#import "base/mac/sdk_forward_declarations.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/sys_string_conversions.h"
#include "skia/ext/skia_utils_mac.h"
#import "ui/base/cocoa/appkit_utils.h"
@@ -28,7 +29,6 @@
#import "ui/gfx/decorated_text_mac.h"
#include "ui/gfx/geometry/rect.h"
#import "ui/gfx/mac/coordinate_conversion.h"
-#include "ui/gfx/path.h"
#import "ui/gfx/path_mac.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
#include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
@@ -60,11 +60,6 @@ gfx::Point MovePointToWindow(const NSPoint& point,
NSHeight(content_rect) - point_in_window.y);
}
-// Returns true if |client| has RTL text.
-bool IsTextRTL(const ui::TextInputClient* client) {
- return client && client->GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
-}
-
// Returns true if |event| may have triggered dismissal of an IME and would
// otherwise be ignored by a ui::TextInputClient when inserted.
bool IsImeTriggerEvent(NSEvent* event) {
@@ -73,117 +68,6 @@ bool IsImeTriggerEvent(NSEvent* event) {
key == ui::VKEY_ESCAPE;
}
-// Returns the boundary rectangle for composition characters in the
-// |requested_range|. Sets |actual_range| corresponding to the returned
-// rectangle. For cases, where there is no composition text or the
-// |requested_range| lies outside the composition range, a zero width rectangle
-// corresponding to the caret bounds is returned. Logic used is similar to
-// RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange(...).
-gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client,
- const gfx::Range& requested_range,
- gfx::Range* actual_range) {
- // NSRange doesn't support reversed ranges.
- DCHECK(!requested_range.is_reversed());
- DCHECK(actual_range);
-
- // Set up default return values, to be returned in case of unusual cases.
- gfx::Rect default_rect;
- *actual_range = gfx::Range::InvalidRange();
- if (!client)
- return default_rect;
-
- default_rect = client->GetCaretBounds();
- default_rect.set_width(0);
-
- // If possible, modify actual_range to correspond to caret position.
- gfx::Range selection_range;
- if (client->GetSelectionRange(&selection_range)) {
- // Caret bounds correspond to end index of selection_range.
- *actual_range = gfx::Range(selection_range.end());
- }
-
- gfx::Range composition_range;
- if (!client->HasCompositionText() ||
- !client->GetCompositionTextRange(&composition_range) ||
- !composition_range.Contains(requested_range))
- return default_rect;
-
- DCHECK(!composition_range.is_reversed());
-
- const size_t from = requested_range.start() - composition_range.start();
- const size_t to = requested_range.end() - composition_range.start();
-
- // Pick the first character's bounds as the initial rectangle, then grow it to
- // the full |requested_range| if possible.
- const bool request_is_composition_end = from == composition_range.length();
- const size_t first_index = request_is_composition_end ? from - 1 : from;
- gfx::Rect union_rect;
- if (!client->GetCompositionCharacterBounds(first_index, &union_rect))
- return default_rect;
-
- // If requested_range is empty, return a zero width rectangle corresponding to
- // it.
- if (from == to) {
- if (request_is_composition_end && !IsTextRTL(client)) {
- // In case of an empty requested range at end of composition, return the
- // rectangle to the right of the last compositioned character.
- union_rect.set_origin(union_rect.top_right());
- }
- union_rect.set_width(0);
- *actual_range = requested_range;
- return union_rect;
- }
-
- // Toolkit-views textfields are always single-line, so no need to check for
- // line breaks.
- for (size_t i = from + 1; i < to; i++) {
- gfx::Rect current_rect;
- if (client->GetCompositionCharacterBounds(i, &current_rect)) {
- union_rect.Union(current_rect);
- } else {
- *actual_range =
- gfx::Range(requested_range.start(), i + composition_range.start());
- return union_rect;
- }
- }
- *actual_range = requested_range;
- return union_rect;
-}
-
-// Returns the string corresponding to |requested_range| for the given |client|.
-// If a gfx::Range::InvalidRange() is passed, the full string stored by |client|
-// is returned. Sets |actual_range| corresponding to the returned string.
-base::string16 AttributedSubstringForRangeHelper(
- const ui::TextInputClient* client,
- const gfx::Range& requested_range,
- gfx::Range* actual_range) {
- // NSRange doesn't support reversed ranges.
- DCHECK(!requested_range.is_reversed());
- DCHECK(actual_range);
-
- base::string16 substring;
- gfx::Range text_range;
- *actual_range = gfx::Range::InvalidRange();
- if (!client || !client->GetTextRange(&text_range))
- return substring;
-
- // gfx::Range::Intersect() behaves a bit weirdly. If B is an empty range
- // contained inside a non-empty range A, B intersection A returns
- // gfx::Range::InvalidRange(), instead of returning B.
- *actual_range = text_range.Contains(requested_range)
- ? requested_range
- : text_range.Intersect(requested_range);
-
- // This is a special case for which the complete string should should be
- // returned. NSTextView also follows this, though the same is not mentioned in
- // NSTextInputClient documentation.
- if (!requested_range.IsValid())
- *actual_range = text_range;
-
- client->GetTextFromRange(*actual_range, &substring);
- return substring;
-}
-
ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
if (action == @selector(undo:))
return ui::TextEditCommand::UNDO;
@@ -256,6 +140,14 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// Returns the native Widget's drag drop client. Possibly null.
- (views_bridge_mac::DragDropClient*)dragDropClient NS_RETURNS_INNER_POINTER;
+// Returns true if there exists a ui::TextInputClient for the currently focused
+// views::View.
+- (BOOL)hasTextInputClient;
+
+// Returns true if there exists a ui::TextInputClient for the currently focused
+// views::View and that client is right-to-left.
+- (BOOL)isTextRTL;
+
// Menu action handlers.
- (void)undo:(id)sender;
- (void)redo:(id)sender;
@@ -270,7 +162,6 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
@implementation BridgedContentView
@synthesize bridge = bridge_;
-@synthesize textInputClient = textInputClient_;
@synthesize drawMenuBackgroundForBlur = drawMenuBackgroundForBlur_;
- (instancetype)initWithBridge:(views::BridgedNativeWidgetImpl*)bridge
@@ -309,6 +200,24 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
return self;
}
+- (ui::TextInputClient*)textInputClient {
+ return bridge_ ? bridge_->host_helper()->GetTextInputClient() : nullptr;
+}
+
+- (BOOL)hasTextInputClient {
+ bool hasTextInputClient = NO;
+ if (bridge_)
+ bridge_->text_input_host()->HasClient(&hasTextInputClient);
+ return hasTextInputClient;
+}
+
+- (BOOL)isTextRTL {
+ bool isRTL = NO;
+ if (bridge_)
+ bridge_->text_input_host()->IsRTL(&isRTL);
+ return isRTL;
+}
+
- (void)dealloc {
// By the time |self| is dealloc'd, it should never be in an NSWindow, and it
// should never be the current input context.
@@ -320,41 +229,13 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)clearView {
- [self setTextInputClient:nullptr];
bridge_ = nullptr;
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
[cursorTrackingArea_.get() clearOwner];
[self removeTrackingArea:cursorTrackingArea_.get()];
}
-- (void)setTextInputClient:(ui::TextInputClient*)newTextInputClient {
- if (pendingTextInputClient_ == newTextInputClient)
- return;
-
- // This method may cause the IME window to dismiss, which may cause it to
- // insert text (e.g. to replace marked text with "real" text). That should
- // happen in the old -inputContext (which AppKit stores a reference to).
- // Unfortunately, the only way to invalidate the the old -inputContext is to
- // invoke -[NSApp updateWindows], which also wants a reference to the _new_
- // -inputContext. So put the new inputContext in |pendingTextInputClient_| and
- // only use it for -inputContext.
- ui::TextInputClient* oldInputClient = textInputClient_;
-
- // Since dismissing an IME may insert text, a misbehaving IME or a
- // ui::TextInputClient that acts on InsertChar() to change focus a second time
- // may invoke -setTextInputClient: recursively; with [NSApp updateWindows]
- // still on the stack. Calling [NSApp updateWindows] recursively may upset
- // an IME. Since the rest of this method is only to decide whether to call
- // updateWindows, and we're already calling it, just bail out.
- if (textInputClient_ != pendingTextInputClient_) {
- pendingTextInputClient_ = newTextInputClient;
- return;
- }
-
- // Start by assuming no need to invoke -updateWindows.
- textInputClient_ = newTextInputClient;
- pendingTextInputClient_ = newTextInputClient;
-
+- (bool)needsUpdateWindows {
// If |self| was being used for the input context, and would now report a
// different input context, manually invoke [NSApp updateWindows]. This is
// necessary because AppKit holds on to a raw pointer to a NSTextInputContext
@@ -365,7 +246,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// the inputContext may change before further event processing.
NSTextInputContext* current = [NSTextInputContext currentInputContext];
if (!current)
- return;
+ return false;
NSTextInputContext* newContext = [self inputContext];
// If the newContext is non-nil, then it can only be [super inputContext]. So
@@ -373,17 +254,10 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// both cases, there's no need to call -updateWindows.
if (newContext) {
DCHECK_EQ(newContext, [super inputContext]);
- return;
+ return false;
}
- if (current == [super inputContext]) {
- DCHECK_NE(oldInputClient, textInputClient_);
- textInputClient_ = oldInputClient;
- [NSApp updateWindows];
- // Note: |pendingTextInputClient_| (and therefore +[NSTextInputContext
- // currentInputContext] may have changed if called recursively.
- textInputClient_ = pendingTextInputClient_;
- }
+ return current == [super inputContext];
}
// If |point| is classified as a draggable background (HTCAPTION), return nil so
@@ -511,8 +385,11 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// If there's an active TextInputClient, schedule the editing command to be
// performed.
- if (textInputClient_ && textInputClient_->IsTextEditCommandEnabled(command))
- textInputClient_->SetTextEditCommandForNextKeyEvent(command);
+ // TODO(https://crbug.com/901490): Add mojo support for ui::TextEditCommand.
+ if ([self textInputClient] &&
+ [self textInputClient] -> IsTextEditCommandEnabled(command)) {
+ [self textInputClient] -> SetTextEditCommandForNextKeyEvent(command);
+ }
[self dispatchKeyEvent:&event];
}
@@ -591,27 +468,14 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
// Forward the |text| to |textInputClient_| if no menu is active.
- if (textInputClient_ && ![self hasActiveMenuController]) {
- // If a single character is inserted by keyDown's call to
- // interpretKeyEvents: then use InsertChar() to allow editing events to be
- // merged. We use ui::VKEY_UNKNOWN as the key code since it's not feasible
- // to determine the correct key code for each unicode character. Also a
- // correct keycode is not needed in the current context. Send ui::EF_NONE as
- // the key modifier since |text| already accounts for the pressed key
- // modifiers.
-
- // Also, note we don't check isFinalInsertForKeyEvent, nor use
- // |keyDownEvent_| to generate the synthetic ui::KeyEvent since: For
- // composed text, [keyDownEvent_ characters] might not be the same as
- // |text|. This is because |keyDownEvent_| will correspond to the event that
- // caused the composition text to be confirmed, say, Return key press.
- if (isCharacterEvent) {
- textInputClient_->InsertChar(
- ui::KeyEvent([text characterAtIndex:0], ui::VKEY_UNKNOWN,
- ui::DomCode::NONE, ui::EF_NONE));
- } else {
- textInputClient_->InsertText(base::SysNSStringToUTF16(text));
- }
+ if ([self hasTextInputClient] && ![self hasActiveMenuController]) {
+ // Note we don't check isFinalInsertForKeyEvent, nor use |keyDownEvent_|
+ // to generate the synthetic ui::KeyEvent since: For composed text,
+ // [keyDownEvent_ characters] might not be the same as |text|. This is
+ // because |keyDownEvent_| will correspond to the event that caused the
+ // composition text to be confirmed, say, Return key press.
+ bridge_->text_input_host()->InsertText(base::SysNSStringToUTF16(text),
+ isCharacterEvent);
// Suppress accelerators that may be bound to this key, since it inserted
// text instead. But note that IME may follow with -insertNewLine:, which
// will resurrect the keyEvent for accelerator handling.
@@ -776,7 +640,11 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
views_bridge_mac::DragDropClient* client = [self dragDropClient];
- return client ? client->DragUpdate(sender) : ui::DragDropTypes::DRAG_NONE;
+ const auto drag_operation =
+ client ? client->DragUpdate(sender) : ui::DragDropTypes::DRAG_NONE;
+ UMA_HISTOGRAM_BOOLEAN("Event.DragDrop.AcceptDragUpdate",
+ drag_operation != ui::DragDropTypes::DRAG_NONE);
+ return drag_operation;
}
- (void)draggingExited:(id<NSDraggingInfo>)sender {
@@ -791,28 +659,11 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (NSTextInputContext*)inputContext {
- // If the textInputClient_ does not exist, return nil since this view does not
- // conform to NSTextInputClient protocol.
- if (!pendingTextInputClient_)
- return nil;
-
- // If a menu is active, and -[NSView interpretKeyEvents:] asks for the
- // input context, return nil. This ensures the action message is sent to
- // the view, rather than any NSTextInputClient a subview has installed.
- if ([self hasActiveMenuController])
+ if (!bridge_)
return nil;
-
- // When not in an editable mode, or while entering passwords
- // (http://crbug.com/23219), we don't want to show IME candidate windows.
- // Returning nil prevents this view from getting messages defined as part of
- // the NSTextInputClient protocol.
- switch (pendingTextInputClient_->GetTextInputType()) {
- case ui::TEXT_INPUT_TYPE_NONE:
- case ui::TEXT_INPUT_TYPE_PASSWORD:
- return nil;
- default:
- return [super inputContext];
- }
+ bool hasTextInputContext = false;
+ bridge_->text_input_host()->HasInputContext(&hasTextInputContext);
+ return hasTextInputContext ? [super inputContext] : nil;
}
// NSResponder implementation.
@@ -1244,25 +1095,23 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)moveToLeftEndOfLine:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveToEndOfLine:sender]
- : [self moveToBeginningOfLine:sender];
+ [self isTextRTL] ? [self moveToEndOfLine:sender]
+ : [self moveToBeginningOfLine:sender];
}
- (void)moveToRightEndOfLine:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveToBeginningOfLine:sender]
- : [self moveToEndOfLine:sender];
+ [self isTextRTL] ? [self moveToBeginningOfLine:sender]
+ : [self moveToEndOfLine:sender];
}
- (void)moveToLeftEndOfLineAndModifySelection:(id)sender {
- IsTextRTL(textInputClient_)
- ? [self moveToEndOfLineAndModifySelection:sender]
- : [self moveToBeginningOfLineAndModifySelection:sender];
+ [self isTextRTL] ? [self moveToEndOfLineAndModifySelection:sender]
+ : [self moveToBeginningOfLineAndModifySelection:sender];
}
- (void)moveToRightEndOfLineAndModifySelection:(id)sender {
- IsTextRTL(textInputClient_)
- ? [self moveToBeginningOfLineAndModifySelection:sender]
- : [self moveToEndOfLineAndModifySelection:sender];
+ [self isTextRTL] ? [self moveToBeginningOfLineAndModifySelection:sender]
+ : [self moveToEndOfLineAndModifySelection:sender];
}
// Graphical Element transposition
@@ -1358,7 +1207,8 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
BOOL canRead = [returnType isEqualToString:utf8Type];
// Valid if (sendType, returnType) is either (string, nil), (nil, string),
// or (string, string).
- BOOL valid = textInputClient_ && ((canWrite && (canRead || !returnType)) ||
+ BOOL valid =
+ [self hasTextInputClient] && ((canWrite && (canRead || !returnType)) ||
(canRead && (canWrite || !sendType)));
return valid
? self
@@ -1373,15 +1223,13 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// either for when it is upgraded.
DCHECK([types containsObject:NSStringPboardType] ||
[types containsObject:base::mac::CFToNSCast(kUTTypeUTF8PlainText)]);
- if (!textInputClient_)
- return NO;
-
- gfx::Range selectionRange;
- if (!textInputClient_->GetSelectionRange(&selectionRange))
- return NO;
+ bool result = NO;
base::string16 text;
- textInputClient_->GetTextFromRange(selectionRange, &text);
+ if (bridge_)
+ bridge_->text_input_host()->GetSelectionText(&result, &text);
+ if (!result)
+ return NO;
return [pboard writeObjects:@[ base::SysUTF16ToNSString(text) ]];
}
@@ -1395,7 +1243,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// NSTextInputClient protocol implementation.
-// IMPORTANT: Always null-check |textInputClient_|. It can change (or be
+// IMPORTANT: Always null-check |[self textInputClient]|. It can change (or be
// cleared) in -setTextInputClient:, which requires informing AppKit that the
// -inputContext has changed and to update its raw pointer. However, the AppKit
// method which does that may also spin a nested run loop communicating with an
@@ -1411,10 +1259,12 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// See https://crbug.com/888782.
if (range.location == NSNotFound)
range.length = 0;
-
- gfx::Range actual_range;
- base::string16 substring = AttributedSubstringForRangeHelper(
- textInputClient_, gfx::Range(range), &actual_range);
+ base::string16 substring;
+ gfx::Range actual_range = gfx::Range::InvalidRange();
+ if (bridge_) {
+ bridge_->text_input_host()->GetAttributedSubstringForRange(
+ gfx::Range(range), &substring, &actual_range);
+ }
if (actualRange) {
// To maintain consistency with NSTextView, return range {0,0} for an out of
// bounds requested range.
@@ -1479,77 +1329,64 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- (NSRect)firstRectForCharacterRange:(NSRange)range
actualRange:(NSRangePointer)actualNSRange {
- gfx::Range actualRange;
- gfx::Rect rect = GetFirstRectForRangeHelper(textInputClient_,
- gfx::Range(range), &actualRange);
+ gfx::Rect rect;
+ gfx::Range actualRange = gfx::Range::InvalidRange();
+ if (bridge_) {
+ bridge_->text_input_host()->GetFirstRectForRange(gfx::Range(range), &rect,
+ &actualRange);
+ }
if (actualNSRange)
*actualNSRange = actualRange.ToNSRange();
return gfx::ScreenRectToNSRect(rect);
}
- (BOOL)hasMarkedText {
- return textInputClient_ && textInputClient_->HasCompositionText();
+ bool hasCompositionText = NO;
+ if (bridge_)
+ bridge_->text_input_host()->HasCompositionText(&hasCompositionText);
+ return hasCompositionText;
}
- (void)insertText:(id)text replacementRange:(NSRange)replacementRange {
- if (!bridge_ || !textInputClient_)
+ if (!bridge_)
return;
-
- textInputClient_->DeleteRange(gfx::Range(replacementRange));
+ bridge_->text_input_host()->DeleteRange(gfx::Range(replacementRange));
[self insertTextInternal:text];
}
- (NSRange)markedRange {
- if (!textInputClient_)
- return NSMakeRange(NSNotFound, 0);
-
- gfx::Range range;
- textInputClient_->GetCompositionTextRange(&range);
+ gfx::Range range = gfx::Range::InvalidRange();
+ if (bridge_)
+ bridge_->text_input_host()->GetCompositionTextRange(&range);
return range.ToNSRange();
}
- (NSRange)selectedRange {
- if (!textInputClient_)
- return NSMakeRange(NSNotFound, 0);
-
- gfx::Range range;
- textInputClient_->GetSelectionRange(&range);
+ gfx::Range range = gfx::Range::InvalidRange();
+ if (bridge_)
+ bridge_->text_input_host()->GetSelectionRange(&range);
return range.ToNSRange();
}
- (void)setMarkedText:(id)text
selectedRange:(NSRange)selectedRange
replacementRange:(NSRange)replacementRange {
- if (!textInputClient_)
+ if (![self hasTextInputClient])
return;
if ([text isKindOfClass:[NSAttributedString class]])
text = [text string];
-
- textInputClient_->DeleteRange(gfx::Range(replacementRange));
- ui::CompositionText composition;
- composition.text = base::SysNSStringToUTF16(text);
- composition.selection = gfx::Range(selectedRange);
-
- // Add an underline with text color and a transparent background to the
- // composition text. TODO(karandeepb): On Cocoa textfields, the target clause
- // of the composition has a thick underlines. The composition text also has
- // discontinous underlines for different clauses. This is also supported in
- // the Chrome renderer. Add code to extract underlines from |text| once our
- // render text implementation supports thick underlines and discontinous
- // underlines for consecutive characters. See http://crbug.com/612675.
- composition.ime_text_spans.push_back(
- ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 0, [text length],
- ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT));
- textInputClient_->SetCompositionText(composition);
+ bridge_->text_input_host()->SetCompositionText(base::SysNSStringToUTF16(text),
+ gfx::Range(selectedRange),
+ gfx::Range(replacementRange));
hasUnhandledKeyDownEvent_ = NO;
}
- (void)unmarkText {
- if (!textInputClient_)
+ if (![self hasTextInputClient])
return;
- textInputClient_->ConfirmCompositionText();
+ bridge_->text_input_host()->ConfirmCompositionText();
hasUnhandledKeyDownEvent_ = NO;
}
@@ -1565,8 +1402,9 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
if (command == ui::TextEditCommand::INVALID_COMMAND)
return NO;
- if (textInputClient_)
- return textInputClient_->IsTextEditCommandEnabled(command);
+ // TODO(https://crbug.com/901490): Add mojo support for ui::TextEditCommand.
+ if ([self textInputClient])
+ return [self textInputClient] -> IsTextEditCommandEnabled(command);
// views::Label does not implement the TextInputClient interface but still
// needs to intercept the Copy and Select All menu actions.
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 4a7ec49d242..cfb144c229b 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
@@ -13,6 +13,10 @@
@class NSView;
+namespace ui {
+class TextInputClient;
+} // namespace ui
+
namespace views_bridge_mac {
class DragDropClient;
@@ -48,15 +52,13 @@ class VIEWS_BRIDGE_MAC_EXPORT BridgedNativeWidgetHostHelper {
gfx::DecoratedText* decorated_word,
gfx::Point* baseline_point) = 0;
- // Returns the vertical position that sheets should be anchored, in pixels
- // from the bottom of the window.
- // TODO(ccameron): This should be either moved to the mojo interface or
- // separated out in such a way as to avoid needing to go through mojo.
- virtual double SheetPositionY() = 0;
-
// Return a pointer to host's DragDropClientMac.
// TODO(ccameron): Drag-drop behavior needs to be implemented over mojo.
virtual DragDropClient* GetDragDropClient() = 0;
+
+ // Return a pointer to the host's ui::TextInputClient.
+ // TODO(ccameron): Remove the needs for this call.
+ virtual ui::TextInputClient* GetTextInputClient() = 0;
};
} // namespace views_bridge_mac
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 13d9a63b873..3f21e108f9d 100644
--- a/chromium/ui/views_bridge_mac/bridged_native_widget_impl.h
+++ b/chromium/ui/views_bridge_mac/bridged_native_widget_impl.h
@@ -16,12 +16,14 @@
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "ui/accelerated_widget_mac/ca_transaction_observer.h"
#include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
+#include "ui/base/cocoa/command_dispatcher.h"
#include "ui/base/cocoa/ns_view_ids.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/display/display_observer.h"
#include "ui/views/views_export.h"
#import "ui/views_bridge_mac/cocoa_mouse_capture_delegate.h"
#include "ui/views_bridge_mac/mojo/bridged_native_widget.mojom.h"
+#include "ui/views_bridge_mac/mojo/text_input_host.mojom.h"
@class BridgedContentView;
@class ModalShowAnimationWithLayer;
@@ -32,6 +34,7 @@ namespace views_bridge_mac {
namespace mojom {
class BridgedNativeWidgetHost;
+class TextInputHost;
} // namespace mojom
class BridgedNativeWidgetHostHelper;
@@ -66,17 +69,20 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
static gfx::Size GetWindowSizeForClientSize(NSWindow* window,
const gfx::Size& size);
- // Retrieve a BridgedNativeWidgetImpl* from its id.
+ // Retrieve a BridgedNativeWidgetImpl* from its id or window.
static BridgedNativeWidgetImpl* GetFromId(uint64_t bridged_native_widget_id);
+ static BridgedNativeWidgetImpl* GetFromNativeWindow(gfx::NativeWindow window);
// Create an NSWindow for the specified parameters.
static base::scoped_nsobject<NativeWidgetMacNSWindow> CreateNSWindow(
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,
- BridgedNativeWidgetHost* host,
- BridgedNativeWidgetHostHelper* host_helper);
+ BridgedNativeWidgetImpl(
+ uint64_t bridged_native_widget_id,
+ BridgedNativeWidgetHost* host,
+ BridgedNativeWidgetHostHelper* host_helper,
+ views_bridge_mac::mojom::TextInputHost* text_input_host);
~BridgedNativeWidgetImpl() override;
// Bind |bridge_mojo_binding_| to |request|, and set the connection error
@@ -92,6 +98,12 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
// this way.
void SetWindow(base::scoped_nsobject<NativeWidgetMacNSWindow> window);
+ // Set the command dispatcher delegate for the window. This will retain
+ // |delegate| for the lifetime of |this|.
+ void SetCommandDispatcher(
+ NSObject<CommandDispatcherDelegate>* delegate,
+ id<UserInterfaceItemCommandHandler> command_handler);
+
// Start moving the window, pinned to the mouse cursor, and monitor events.
// Return true on mouse up or false on premature termination via EndMoveLoop()
// or when window is destroyed during the drag.
@@ -147,6 +159,9 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
BridgedContentView* ns_view() { return bridged_view_; }
BridgedNativeWidgetHost* host() { return host_; }
BridgedNativeWidgetHostHelper* host_helper() { return host_helper_; }
+ views_bridge_mac::mojom::TextInputHost* text_input_host() const {
+ return text_input_host_;
+ }
NSWindow* ns_window();
views_bridge_mac::DragDropClient* drag_drop_client();
@@ -185,6 +200,7 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
void CreateWindow(
views_bridge_mac::mojom::CreateWindowParamsPtr params) override;
void SetParent(uint64_t parent_id) override;
+ void ShowEmojiPanel() override;
void InitWindow(views_bridge_mac::mojom::BridgedNativeWidgetInitParamsPtr
params) override;
void InitCompositorView() override;
@@ -226,9 +242,9 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
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.
- void SetTextInputClient(ui::TextInputClient* text_input_client);
+ // Return true if [NSApp updateWindows] needs to be called after updating the
+ // TextInputClient.
+ bool NeedsUpdateWindows();
// Compute the window and content size, and forward them to |host_|. This will
// update widget and compositor size.
@@ -272,8 +288,14 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
const uint64_t id_;
BridgedNativeWidgetHost* const host_; // Weak. Owns this.
BridgedNativeWidgetHostHelper* const host_helper_; // Weak, owned by |host_|.
+ views_bridge_mac::mojom::TextInputHost* const
+ text_input_host_; // Weak, owned by |host_|.
+
base::scoped_nsobject<NativeWidgetMacNSWindow> window_;
base::scoped_nsobject<ViewsNSWindowDelegate> window_delegate_;
+ base::scoped_nsobject<NSObject<CommandDispatcherDelegate>>
+ window_command_dispatcher_delegate_;
+
base::scoped_nsobject<BridgedContentView> bridged_view_;
std::unique_ptr<ui::ScopedNSViewIdMapping> bridged_view_id_mapping_;
base::scoped_nsobject<ModalShowAnimationWithLayer> show_animation_;
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 1f368c2fb23..4b013297d2c 100644
--- a/chromium/ui/views_bridge_mac/bridged_native_widget_impl.mm
+++ b/chromium/ui/views_bridge_mac/bridged_native_widget_impl.mm
@@ -19,7 +19,9 @@
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#include "ui/base/cocoa/cocoa_base_utils.h"
#import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
+#include "ui/base/cocoa/remote_accessibility_api.h"
#import "ui/base/cocoa/window_size_constants.h"
+#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/base/hit_test.h"
#include "ui/base/layout.h"
#include "ui/base/ui_base_switches.h"
@@ -245,6 +247,17 @@ BridgedNativeWidgetImpl* BridgedNativeWidgetImpl::GetFromId(
}
// static
+BridgedNativeWidgetImpl* BridgedNativeWidgetImpl::GetFromNativeWindow(
+ gfx::NativeWindow native_window) {
+ NSWindow* window = native_window.GetNativeNSWindow();
+ if (NativeWidgetMacNSWindow* widget_window =
+ base::mac::ObjCCast<NativeWidgetMacNSWindow>(window)) {
+ return GetFromId([widget_window bridgedNativeWidgetId]);
+ }
+ return nullptr;
+}
+
+// static
base::scoped_nsobject<NativeWidgetMacNSWindow>
BridgedNativeWidgetImpl::CreateNSWindow(
const views_bridge_mac::mojom::CreateWindowParams* params) {
@@ -287,10 +300,12 @@ BridgedNativeWidgetImpl::CreateNSWindow(
BridgedNativeWidgetImpl::BridgedNativeWidgetImpl(
uint64_t bridged_native_widget_id,
BridgedNativeWidgetHost* host,
- BridgedNativeWidgetHostHelper* host_helper)
+ BridgedNativeWidgetHostHelper* host_helper,
+ views_bridge_mac::mojom::TextInputHost* text_input_host)
: id_(bridged_native_widget_id),
host_(host),
host_helper_(host_helper),
+ text_input_host_(text_input_host),
bridge_mojo_binding_(this) {
DCHECK(GetIdToWidgetImplMap().find(id_) == GetIdToWidgetImplMap().end());
GetIdToWidgetImplMap().insert(std::make_pair(id_, this));
@@ -327,6 +342,14 @@ void BridgedNativeWidgetImpl::SetWindow(
ui::CATransactionCoordinator::Get().AddPreCommitObserver(this);
}
+void BridgedNativeWidgetImpl::SetCommandDispatcher(
+ NSObject<CommandDispatcherDelegate>* delegate,
+ id<UserInterfaceItemCommandHandler> command_handler) {
+ window_command_dispatcher_delegate_.reset([delegate retain]);
+ [window_ setCommandDispatcherDelegate:delegate];
+ [window_ setCommandHandler:command_handler];
+}
+
void BridgedNativeWidgetImpl::SetParent(uint64_t new_parent_id) {
// Remove from the old parent.
if (parent_) {
@@ -362,6 +385,10 @@ void BridgedNativeWidgetImpl::SetParent(uint64_t new_parent_id) {
[parent_->ns_window() addChildWindow:window_ ordered:NSWindowAbove];
}
+void BridgedNativeWidgetImpl::ShowEmojiPanel() {
+ ui::ShowEmojiPanel();
+}
+
void BridgedNativeWidgetImpl::CreateWindow(
views_bridge_mac::mojom::CreateWindowParamsPtr params) {
SetWindow(CreateNSWindow(params.get()));
@@ -501,6 +528,11 @@ void BridgedNativeWidgetImpl::CreateContentView(uint64_t ns_view_id,
// this should be treated as an error and caught early.
CHECK(bridged_view_);
+ // Send the accessibility tokens for the NSView now that it exists.
+ host_->SetRemoteAccessibilityTokens(
+ ui::RemoteAccessibility::GetTokenForLocalElement(window_),
+ ui::RemoteAccessibility::GetTokenForLocalElement(bridged_view_));
+
// Beware: This view was briefly removed (in favor of a bare CALayer) in
// crrev/c/1236675. The ordering of unassociated layers relative to NSView
// layers is undefined on macOS 10.12 and earlier, so the compositor layer
@@ -516,6 +548,7 @@ void BridgedNativeWidgetImpl::CreateContentView(uint64_t ns_view_id,
[compositor_view setWantsLayer:YES];
[bridged_view_ addSubview:compositor_view];
+ [bridged_view_ setWantsLayer:YES];
[window_ setContentView:bridged_view_];
}
@@ -742,6 +775,9 @@ void BridgedNativeWidgetImpl::SetCursor(NSCursor* cursor) {
}
void BridgedNativeWidgetImpl::OnWindowWillClose() {
+ [window_ setCommandHandler:nil];
+ [window_ setCommandDispatcherDelegate:nil];
+
ui::CATransactionCoordinator::Get().RemovePreCommitObserver(this);
host_->OnWindowWillClose();
@@ -1015,12 +1051,7 @@ bool BridgedNativeWidgetImpl::ShouldRunCustomAnimationFor(
}
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];
+ return [[window_ commandDispatcher] redispatchKeyEvent:event];
}
NSWindow* BridgedNativeWidgetImpl::ns_window() {
@@ -1156,9 +1187,8 @@ void BridgedNativeWidgetImpl::UpdateTooltip() {
[bridged_view_ updateTooltipIfRequiredAt:point];
}
-void BridgedNativeWidgetImpl::SetTextInputClient(
- ui::TextInputClient* text_input_client) {
- [bridged_view_ setTextInputClient:text_input_client];
+bool BridgedNativeWidgetImpl::NeedsUpdateWindows() {
+ return [bridged_view_ needsUpdateWindows];
}
void BridgedNativeWidgetImpl::RedispatchKeyEvent(
@@ -1308,11 +1338,16 @@ void BridgedNativeWidgetImpl::ShowAsModalSheet() {
// Since |this| may destroy [window_ delegate], use |window_| itself as the
// delegate, which will forward to ViewsNSWindowDelegate if |this| is still
// alive (i.e. it has not set the window delegate to nil).
+ // TODO(crbug.com/841631): Migrate to `[NSWindow
+ // beginSheet:completionHandler:]` instead of this method.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[NSApp beginSheet:window_
modalForWindow:parent_window
modalDelegate:window_
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:nullptr];
+#pragma clang diagnostic pop
}
} // namespace views
diff --git a/chromium/ui/views_bridge_mac/mojo/alert.mojom b/chromium/ui/views_bridge_mac/mojo/alert.mojom
new file mode 100644
index 00000000000..7f49f4288bd
--- /dev/null
+++ b/chromium/ui/views_bridge_mac/mojo/alert.mojom
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module views_bridge_mac.mojom;
+
+import "mojo/public/mojom/base/string16.mojom";
+
+struct AlertBridgeInitParams {
+ // The dialog title and text.
+ mojo_base.mojom.String16 title;
+ mojo_base.mojom.String16 message_text;
+
+ // Set if the application icon should be hidden.
+ bool hide_application_icon;
+
+ // Text for the primary button (which is also the default button).
+ mojo_base.mojom.String16 primary_button_text;
+
+ // Text for the secondary (non-default) button. If not set, then there is only
+ // one button for this alert.
+ mojo_base.mojom.String16? secondary_button_text;
+
+ // Default text for the text field. If not set, then there is no text field
+ // for this alert.
+ mojo_base.mojom.String16? text_field_text;
+
+ // The text for the checkbox. If not set, then there is no checkbox for this
+ // alert.
+ mojo_base.mojom.String16? check_box_text;
+};
+
+// Disposition of alert window.
+enum AlertDisposition {
+ // Default button was pressed.
+ PRIMARY_BUTTON,
+ // Secondary button was pressed.
+ SECONDARY_BUTTON,
+ // The window was closed without a selection being made.
+ CLOSE,
+};
+
+interface AlertBridge {
+ // Initialize and show the alert. Return in |disposition| is how the window
+ // was dismissed. Return in |text_field_value| the value of the text field
+ // shown in the alert (if any). Return true in |check_box_value| only if the
+ // alert had a checkbox and it was checked.
+ Show(AlertBridgeInitParams params) =>
+ (AlertDisposition disposition, mojo_base.mojom.String16 text_field_value,
+ bool check_box_value);
+};
diff --git a/chromium/ui/views_bridge_mac/mojo/bridge_factory.mojom b/chromium/ui/views_bridge_mac/mojo/bridge_factory.mojom
index 246ba5bb289..bbb596f9c68 100644
--- a/chromium/ui/views_bridge_mac/mojo/bridge_factory.mojom
+++ b/chromium/ui/views_bridge_mac/mojo/bridge_factory.mojom
@@ -4,17 +4,23 @@
module views_bridge_mac.mojom;
+import "ui/views_bridge_mac/mojo/alert.mojom";
import "ui/views_bridge_mac/mojo/bridged_native_widget.mojom";
import "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom";
+import "ui/views_bridge_mac/mojo/text_input_host.mojom";
// The interface through which a bridge is created and connected to its host.
interface BridgeFactory {
+ // Create a bridge for an NSAlert. The resulting object owns its own lifetime.
+ CreateAlert(AlertBridge& alert_bridge_request);
+
// Create a bridge for a native widget. The resulting object will be owned by
// the connection for |host|. Closing that connection will result in deleting
// the bridge.
CreateBridgedNativeWidget(
uint64 bridge_id,
associated BridgedNativeWidget& bridge_request,
- associated BridgedNativeWidgetHost host);
+ associated BridgedNativeWidgetHost host,
+ associated TextInputHost text_input_host);
};
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 6a583e8f983..637cf66a926 100644
--- a/chromium/ui/views_bridge_mac/mojo/bridged_native_widget.mojom
+++ b/chromium/ui/views_bridge_mac/mojo/bridged_native_widget.mojom
@@ -79,7 +79,7 @@ struct BridgedNativeWidgetInitParams {
};
// The interface through which a NativeWidgetMac may interact with an NSWindow
-// in another process.
+// (possibly in a process separate from the browser process).
interface BridgedNativeWidget {
// Create and set the NSWindow for the bridge.
CreateWindow(CreateWindowParams params);
@@ -88,6 +88,9 @@ interface BridgedNativeWidget {
// this BridgedNativeWidget.
SetParent(uint64 parent_id);
+ // Show the emoji panel for the NSWindow's process.
+ ShowEmojiPanel();
+
// Initialize the window's style.
InitWindow(BridgedNativeWidgetInitParams params);
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 5f08a4554e8..bf9391ce1c7 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
@@ -5,14 +5,39 @@
module views_bridge_mac.mojom;
import "mojo/public/mojom/base/string16.mojom";
+import "ui/base/accelerators/mojo/accelerator.mojom";
import "ui/base/mojo/ui_base_types.mojom";
+import "ui/base/mojo/window_open_disposition.mojom";
import "ui/display/mojo/display.mojom";
import "ui/events/mojo/event.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/mojo/ca_layer_params.mojom";
-// The interface through which a NativeWidgetMac may interact with an NSWindow
-// in another process.
+struct ValidateUserInterfaceItemResult {
+ // Whether or not the specified sender should be enabled.
+ bool enable;
+
+ // If true, then the item should be disabled if there exists no key equivalent
+ // for the item.
+ bool disable_if_has_no_key_equivalent;
+
+ // The new title to set for the item (unset if the title is not to be
+ // changed).
+ mojo_base.mojom.String16? new_title;
+
+ // Whether or not to change the hidden state for the item, and the new hidden
+ // state to set.
+ bool set_hidden_state;
+ bool new_hidden_state;
+
+ // Whether or not to change the toggled state for the item, and the new toggle
+ // state to set.
+ bool set_toggle_state;
+ bool new_toggle_state;
+};
+
+// The interface through which an NSWindow (possibly in a process separate from
+// the browser process) may interact with a NativeWidgetMac.
interface BridgedNativeWidgetHost {
// Update the views::Widget, ui::Compositor and ui::Layer's visibility.
OnVisibilityChanged(bool visible);
@@ -25,6 +50,11 @@ interface BridgedNativeWidgetHost {
// bounds from OnWindowGeometryChanged.
OnViewSizeChanged(gfx.mojom.Size new_size);
+ // The vertical position from which sheets should be anchored, from the top
+ // of the content view.
+ [Sync]
+ GetSheetOffsetY() => (int32 offset_y);
+
// Indicate if full keyboard accessibility is needed and update focus if
// needed.
SetKeyboardAccessible(bool enabled);
@@ -167,12 +197,39 @@ interface BridgedNativeWidgetHost {
// 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.
+ // Send the token for the NSWindow and NSView for this widget.
+ SetRemoteAccessibilityTokens(
+ array<uint8> window_token, array<uint8> view_token);
+
+ // Return in |element_token| the token for the root views AX node for this
+ // view and in |host_pid| the pid for the host process.
[Sync]
- GetAccessibilityTokens(array<uint8> window_token,
- array<uint8> view_token) =>
+ GetRootViewAccessibilityToken() =>
(int64 host_pid, array<uint8> element_token);
+
+ // Return the result for -[NSUserInterfaceValidations
+ // validateUserInterfaceItem] for a given command, along with any state for
+ // that item that should be updated.
+ [Sync]
+ ValidateUserInterfaceItem(int32 command) =>
+ (ValidateUserInterfaceItemResult result);
+
+ // Execute the chrome command |command| with |window_open_disposition|. If
+ // |is_before_first_responder| then only call ExecuteCommand if the command
+ // is reserved and extension shortcut handling is not suspended. Returns in
+ // |was_executed| whether or not ExecuteCommand was called (regardless of what
+ // the return value for ExecuteCommand was).
+ [Sync]
+ ExecuteCommand(int32 command,
+ ui.mojom.WindowOpenDisposition window_open_disposition,
+ bool is_before_first_responder) => (bool was_executed);
+
+ // Give the widget's FocusManager a chance to to handle the specified
+ // accelerator. If |require_priority_handler| is true, the only send the
+ // accelerator to the FocusManager if the FocusManager has a priority handler
+ // for the specified accelerator.
+ [Sync]
+ HandleAccelerator(ui.mojom.Accelerator accelerator,
+ bool require_priority_handler) =>
+ (bool was_handled);
};
diff --git a/chromium/ui/views_bridge_mac/mojo/text_input_host.mojom b/chromium/ui/views_bridge_mac/mojo/text_input_host.mojom
new file mode 100644
index 00000000000..b721d6e590e
--- /dev/null
+++ b/chromium/ui/views_bridge_mac/mojo/text_input_host.mojom
@@ -0,0 +1,81 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module views_bridge_mac.mojom;
+
+import "mojo/public/mojom/base/string16.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
+import "ui/gfx/range/mojo/range.mojom";
+
+// Interface exposing a views::Widget's currently-focused views::View's
+// ui::TextInputClient to the NSView corresponding to that views::Widget.
+interface TextInputHost {
+ // Returns true in |has_client| if there exists an active ui::TextInputClient
+ // for the focused views::View.
+ [Sync]
+ HasClient() => (bool has_client);
+
+ // Returns true in |has_input_context|| if -[NSView inputContext] should
+ // return a non-nil value.
+ [Sync]
+ HasInputContext() => (bool has_input_context);
+
+ // Returns true in |is_rtl| if there exists an active ui::TextInputClient and
+ // that ui::TextInputClient is RTL (right-to-left).
+ [Sync]
+ IsRTL() => (bool is_rtl);
+
+ // Retrieves the character range of current selection in the current text
+ // input. Returns an invalid range if the information cannot be retrieved
+ // right now or if the selected text is not in the focused views::View.
+ [Sync]
+ GetSelectionRange() => (gfx.mojom.Range range);
+
+ // Retrieves the currently selected text, and stores it in |text|. Returns
+ // false in |result| if there was no selection.
+ [Sync]
+ GetSelectionText() => (bool result, mojo_base.mojom.String16 text);
+
+ // Inserts a given text at the insertion point.
+ InsertText(mojo_base.mojom.String16 text, bool as_character);
+
+ // Deletes contents in the given character range.
+ DeleteRange(gfx.mojom.Range range);
+
+ // Sets composition text in the current ui::TextInputClient to |text| with
+ // selection range |selected_range|, and delete the content of
+ // |replacement_range|.
+ SetCompositionText(mojo_base.mojom.String16 text,
+ gfx.mojom.Range selected_range,
+ gfx.mojom.Range replacement_range);
+
+ // Converts current composition text into final content.
+ ConfirmCompositionText();
+
+ // Returns true in |has_composition_text| if there is composition text.
+ [Sync]
+ HasCompositionText() => (bool has_composition_text);
+
+ // Returns in |composition_range| the character range of current composition
+ // text.
+ [Sync]
+ GetCompositionTextRange() => (gfx.mojom.Range composition_range);
+
+ // Returns in |text| the string corresponding to |requested_range| for current
+ // ui::TextInputClient. If a gfx::Range::InvalidRange() is passed, the full
+ // string stored by for the current ui::TextInputClient is returned. Sets
+ // |actual_range| corresponding to the returned string.
+ [Sync]
+ GetAttributedSubstringForRange(gfx.mojom.Range requested_range) =>
+ (mojo_base.mojom.String16 text, gfx.mojom.Range actual_range);
+
+ // Returns in |rect| the boundary rectangle for composition characters in the
+ // |requested_range|. Sets |actual_range| corresponding to the returned
+ // rectangle. For cases where there is no composition text or the
+ // |requested_range| lies outside the composition range, a zero width
+ // rectangle corresponding to the caret bounds is returned.
+ [Sync]
+ GetFirstRectForRange(gfx.mojom.Range requested_range) =>
+ (gfx.mojom.Rect rect, gfx.mojom.Range actual_range);
+};
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 954ee2f0445..54ec2c8a1bd 100644
--- a/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.mm
+++ b/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.mm
@@ -271,6 +271,13 @@
return touchBarDelegate_ ? [touchBarDelegate_ makeTouchBar] : nil;
}
+// On newer SDKs, _canMiniaturize respects NSMiniaturizableWindowMask in the
+// window's styleMask. Views assumes that Widgets can always be minimized,
+// regardless of their window style, so override that behavior here.
+- (BOOL)_canMiniaturize {
+ return YES;
+}
+
// CommandDispatchingWindow implementation.
- (void)setCommandHandler:(id<UserInterfaceItemCommandHandler>)commandHandler {
diff --git a/chromium/ui/views_bridge_mac/views_nswindow_delegate.mm b/chromium/ui/views_bridge_mac/views_nswindow_delegate.mm
index 7d1fbfa9925..56869ebc18b 100644
--- a/chromium/ui/views_bridge_mac/views_nswindow_delegate.mm
+++ b/chromium/ui/views_bridge_mac/views_nswindow_delegate.mm
@@ -196,15 +196,18 @@
- (NSRect)window:(NSWindow*)window
willPositionSheet:(NSWindow*)sheet
usingRect:(NSRect)defaultSheetLocation {
- // TODO(ccameron): This should go through the BridgedNativeWidgetHost
- // interface.
- CGFloat sheetPositionY = parent_->host_helper()->SheetPositionY();
+ int32_t sheetPositionY = 0;
+ parent_->host()->GetSheetOffsetY(&sheetPositionY);
+ NSView* view = [window contentView];
+ NSPoint pointInView =
+ NSMakePoint(0, NSMaxY([view bounds]) - sheetPositionY);
+ NSPoint pointInWindow = [view convertPoint:pointInView toView:nil];
// As per NSWindowDelegate documentation, the origin indicates the top left
// point of the host frame in window coordinates. The width changes the
// animation from vertical to trapezoid if it is smaller than the width of the
// dialog. The height is ignored but should be set to zero.
- return NSMakeRect(0, sheetPositionY, NSWidth(defaultSheetLocation), 0);
+ return NSMakeRect(0, pointInWindow.y, NSWidth(defaultSheetLocation), 0);
}
@end
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 6b180f98d8b..3f5be001be1 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
@@ -7,6 +7,7 @@
#include <utility>
#include "base/run_loop.h"
+#include "build/build_config.h"
#include "content/public/browser/context_factory.h"
#include "content/shell/browser/shell_browser_context.h"
#include "ui/base/ime/input_method_initializer.h"
@@ -25,6 +26,10 @@ ViewsContentClientMainParts::ViewsContentClientMainParts(
ViewsContentClientMainParts::~ViewsContentClientMainParts() {
}
+#if !defined(OS_MACOSX)
+void ViewsContentClientMainParts::PreCreateMainMessageLoop() {}
+#endif
+
void ViewsContentClientMainParts::PreMainMessageLoopRun() {
ui::MaterialDesignController::Initialize();
ui::InitializeInputMethodForTesting();
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 fec1081d4fc..346299b53bb 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
@@ -34,6 +34,9 @@ class ViewsContentClientMainParts : public content::BrowserMainParts {
const content::MainFunctionParams& content_params,
ViewsContentClient* views_content_client);
+ // Invoked before the BrowserMainLoop constructor.
+ static void PreCreateMainMessageLoop();
+
~ViewsContentClientMainParts() override;
// content::BrowserMainParts:
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts_mac.mm b/chromium/ui/views_content_client/views_content_client_main_parts_mac.mm
index bceaa9c12d0..d574099be5e 100644
--- a/chromium/ui/views_content_client/views_content_client_main_parts_mac.mm
+++ b/chromium/ui/views_content_client/views_content_client_main_parts_mac.mm
@@ -10,6 +10,7 @@
#include "base/path_service.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/content_paths.h"
+#include "content/shell/browser/shell_application_mac.h"
#include "content/shell/browser/shell_browser_context.h"
#include "ui/views_content_client/views_content_client.h"
#include "ui/views_content_client/views_content_client_main_parts.h"
@@ -84,6 +85,15 @@ ViewsContentClientMainParts* ViewsContentClientMainParts::Create(
new ViewsContentClientMainPartsMac(content_params, views_content_client);
}
+// static
+void ViewsContentClientMainParts::PreCreateMainMessageLoop() {
+ // Simply instantiating an instance of ShellCrApplication serves to register
+ // it as the application class. Do make sure that no other code has done this
+ // first, though.
+ CHECK_EQ(NSApp, nil);
+ [ShellCrApplication sharedApplication];
+}
+
} // namespace ui
@implementation ViewsContentClientAppController
@@ -114,6 +124,8 @@ ViewsContentClientMainParts* ViewsContentClientMainParts::Create(
keyEquivalent:@"q"];
[appMenuItem setSubmenu:appMenu];
+ CHECK([NSApp isKindOfClass:[ShellCrApplication class]]);
+
task_.Run();
}
diff --git a/chromium/ui/views_content_client/views_content_main_delegate.cc b/chromium/ui/views_content_client/views_content_main_delegate.cc
index fe8ddf175ec..f458830416f 100644
--- a/chromium/ui/views_content_client/views_content_main_delegate.cc
+++ b/chromium/ui/views_content_client/views_content_main_delegate.cc
@@ -15,6 +15,7 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_paths.h"
#include "ui/views_content_client/views_content_browser_client.h"
+#include "ui/views_content_client/views_content_client_main_parts.h"
#if defined(OS_WIN)
#include "base/logging_win.h"
@@ -79,6 +80,11 @@ void ViewsContentMainDelegate::PreSandboxStartup() {
}
}
+void ViewsContentMainDelegate::PreCreateMainMessageLoop() {
+ content::ContentMainDelegate::PreCreateMainMessageLoop();
+ ViewsContentClientMainParts::PreCreateMainMessageLoop();
+}
+
content::ContentBrowserClient*
ViewsContentMainDelegate::CreateContentBrowserClient() {
browser_client_.reset(new ViewsContentBrowserClient(views_content_client_));
diff --git a/chromium/ui/views_content_client/views_content_main_delegate.h b/chromium/ui/views_content_client/views_content_main_delegate.h
index 4655719ba9a..4ef4396ecc6 100644
--- a/chromium/ui/views_content_client/views_content_main_delegate.h
+++ b/chromium/ui/views_content_client/views_content_main_delegate.h
@@ -24,6 +24,7 @@ class ViewsContentMainDelegate : public content::ContentMainDelegate {
// content::ContentMainDelegate implementation
bool BasicStartupComplete(int* exit_code) override;
void PreSandboxStartup() override;
+ void PreCreateMainMessageLoop() override;
content::ContentBrowserClient* CreateContentBrowserClient() override;
private:
diff --git a/chromium/ui/webui/resources/cr_components/.eslintrc.js b/chromium/ui/webui/resources/.eslintrc.js
index 25e21f992eb..ee593a0091e 100644
--- a/chromium/ui/webui/resources/cr_components/.eslintrc.js
+++ b/chromium/ui/webui/resources/.eslintrc.js
@@ -9,5 +9,6 @@ module.exports = {
},
'rules': {
'no-var': 'error',
+ 'prefer-const': 'error',
},
};
diff --git a/chromium/ui/webui/resources/PRESUBMIT.py b/chromium/ui/webui/resources/PRESUBMIT.py
index 5252e6b819e..92ee47dcad6 100644
--- a/chromium/ui/webui/resources/PRESUBMIT.py
+++ b/chromium/ui/webui/resources/PRESUBMIT.py
@@ -15,7 +15,7 @@ def CheckChangeOnCommit(input_api, output_api):
def _CheckForTranslations(input_api, output_api):
shared_keywords = ['i18n(']
html_keywords = shared_keywords + ['$118n{']
- js_keywords = shared_keywords + ['I18nBehavior', 'loadTimeData.']
+ js_keywords = shared_keywords + ['I18nBehavior', 'loadTimeData.get']
errors = []
diff --git a/chromium/ui/webui/resources/cr_components/BUILD.gn b/chromium/ui/webui/resources/cr_components/BUILD.gn
index b39708e6607..3773a9e8cf0 100644
--- a/chromium/ui/webui/resources/cr_components/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/BUILD.gn
@@ -7,6 +7,7 @@ import("//third_party/closure_compiler/compile_js.gni")
group("closure_compile") {
deps = [
"certificate_manager:closure_compile",
+ "managed_footnote:closure_compile",
]
if (is_chromeos) {
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.js b/chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.js
index c33d5558efa..596f6ff58c1 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.js
@@ -60,7 +60,7 @@ Polymer({
onOkTap_: function() {
this.$.spinner.active = true;
- var whenDone = this.model.id ?
+ const whenDone = this.model.id ?
this.browserProxy_.editCaCertificateTrust(
this.model.id, this.$.ssl.checked, this.$.email.checked,
this.$.objSign.checked) :
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.js
index f914b0865ad..2de56348fac 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.js
@@ -42,7 +42,7 @@ Polymer({
* @param {string} localizedMessageId
* @return {string}
*/
- var getString = localizedMessageId =>
+ const getString = localizedMessageId =>
loadTimeData.getStringF(localizedMessageId, this.model.name);
switch (this.certificateType) {
@@ -63,7 +63,7 @@ Polymer({
* @return {string}
*/
getDescriptionText_: function() {
- var getString = loadTimeData.getString.bind(loadTimeData);
+ const getString = loadTimeData.getString.bind(loadTimeData);
switch (this.certificateType) {
case CertificateType.PERSONAL:
return getString('certificateManagerDeleteUserDescription');
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_list.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_list.js
index 8bd3109625d..fd8dd24d8a4 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_list.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_list.js
@@ -49,8 +49,9 @@ Polymer({
* @private
*/
getDescription_: function() {
- if (this.certificates.length == 0)
+ if (this.certificates.length == 0) {
return this.i18n('certificateManagerNoCertificates');
+ }
switch (this.certificateType) {
case CertificateType.PERSONAL:
@@ -145,13 +146,14 @@ Polymer({
* @private
*/
handleImport_: function(useHardwareBacked, anchor) {
- var browserProxy =
+ const browserProxy =
certificate_manager.CertificatesBrowserProxyImpl.getInstance();
if (this.certificateType == CertificateType.PERSONAL) {
browserProxy.importPersonalCertificate(useHardwareBacked)
.then(showPasswordPrompt => {
- if (showPasswordPrompt)
+ if (showPasswordPrompt) {
this.dispatchImportActionEvent_(null, anchor);
+ }
}, this.onRejected_.bind(this, anchor));
} else if (this.certificateType == CertificateType.CA) {
browserProxy.importCaCertificate().then(certificateName => {
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js
index 9ef17af7cd9..09375d206af 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js
@@ -160,7 +160,8 @@ Polymer({
});
this.addEventListener('certificates-error', event => {
- var detail = /** @type {!CertificatesErrorEventDetail} */ (event.detail);
+ const detail =
+ /** @type {!CertificatesErrorEventDetail} */ (event.detail);
this.errorDialogModel_ = detail.error;
this.openDialog_(
'certificates-error-dialog', 'showErrorDialog_', detail.anchor);
@@ -184,11 +185,12 @@ Polymer({
* @private
*/
openDialog_: function(dialogTagName, domIfBooleanName, anchor) {
- if (anchor)
+ if (anchor) {
this.activeDialogAnchor_ = anchor;
+ }
this.set(domIfBooleanName, true);
this.async(() => {
- var dialog = this.$$(dialogTagName);
+ const dialog = this.$$(dialogTagName);
dialog.addEventListener('close', () => {
this.set(domIfBooleanName, false);
cr.ui.focusWithoutInk(assert(this.activeDialogAnchor_));
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager_types.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager_types.js
index 76d448770cf..767af638208 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager_types.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_manager_types.js
@@ -15,7 +15,7 @@
* anchor: !HTMLElement
* }}
*/
-var CertificateActionEventDetail;
+let CertificateActionEventDetail;
/**
* The payload of the 'certificates-error' event.
@@ -24,13 +24,13 @@ var CertificateActionEventDetail;
* anchor: ?HTMLElement
* }}
*/
-var CertificatesErrorEventDetail;
+let CertificatesErrorEventDetail;
/**
* Enumeration of actions that require a popup menu to be shown to the user.
* @enum {number}
*/
-var CertificateAction = {
+const CertificateAction = {
DELETE: 0,
EDIT: 1,
EXPORT_PERSONAL: 2,
@@ -41,4 +41,4 @@ var CertificateAction = {
* The name of the event fired when a certificate action is selected from the
* dropdown menu. CertificateActionEventDetail is passed as the event detail.
*/
-var CertificateActionEvent = 'certificate-action';
+const CertificateActionEvent = 'certificate-action';
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.js
index b605ee7c22a..a927ffa6608 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.js
@@ -62,7 +62,7 @@ Polymer({
/** @private */
validate_: function() {
- var isValid =
+ const isValid =
this.password_ != '' && this.password_ == this.confirmPassword_;
this.$.ok.disabled = !isValid;
},
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
index 2407809c344..ee947c42550 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
@@ -42,21 +42,21 @@
<cr-lazy-render id="menu">
<template>
<cr-action-menu>
- <button slot="item" class="dropdown-item" id="view"
+ <button class="dropdown-item" id="view"
on-tap="onViewTap_">
[[i18n('certificateManagerView')]]
</button>
- <button slot="item" class="dropdown-item" id="edit"
+ <button class="dropdown-item" id="edit"
hidden$="[[!canEdit_(certificateType, model)]]"
on-tap="onEditTap_">
[[i18n('edit')]]
</button>
- <button slot="item" class="dropdown-item" id="export"
+ <button class="dropdown-item" id="export"
hidden$="[[!canExport_(certificateType, model)]]"
on-tap="onExportTap_">
[[i18n('certificateManagerExport')]]
</button>
- <button slot="item" class="dropdown-item" id="delete"
+ <button class="dropdown-item" id="delete"
hidden$="[[!canDelete_(model)]]"
on-tap="onDeleteTap_">
[[i18n('certificateManagerDelete')]]
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
index 3f2c5423f34..ddc023ed1af 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
@@ -144,7 +144,7 @@ Polymer({
/** @private */
onDotsTap_: function() {
- var actionMenu = /** @type {!CrActionMenuElement} */ (this.$.menu.get());
+ const actionMenu = /** @type {!CrActionMenuElement} */ (this.$.menu.get());
actionMenu.showAt(this.$.dots);
},
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js
index 826b4bb78e0..33e780de083 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js
@@ -19,7 +19,7 @@
* }}
* @see chrome/browser/ui/webui/settings/certificates_handler.cc
*/
-var CertificateSubnode;
+let CertificateSubnode;
/**
* A data structure describing a certificate that is currently being imported,
@@ -28,7 +28,7 @@ var CertificateSubnode;
* name: string,
* }}
*/
-var NewCertificateSubNode;
+let NewCertificateSubNode;
/**
* Top-level grouping node in a certificate list, representing an organization
@@ -43,7 +43,7 @@ var NewCertificateSubNode;
* }}
* @see chrome/browser/ui/webui/settings/certificates_handler.cc
*/
-var CertificatesOrgGroup;
+let CertificatesOrgGroup;
/**
* @typedef {{
@@ -52,7 +52,7 @@ var CertificatesOrgGroup;
* objSign: boolean
* }}
*/
-var CaTrustInfo;
+let CaTrustInfo;
/**
* Generic error returned from C++ via a Promise reject callback.
@@ -62,13 +62,13 @@ var CaTrustInfo;
* }}
* @see chrome/browser/ui/webui/settings/certificates_handler.cc
*/
-var CertificatesError;
+let CertificatesError;
/**
* Enumeration of all possible certificate types.
* @enum {string}
*/
-var CertificateType = {
+const CertificateType = {
CA: 'ca',
OTHER: 'other',
PERSONAL: 'personal',
@@ -86,7 +86,7 @@ var CertificateType = {
* }}
* @see chrome/browser/ui/webui/settings/certificates_handler.cc
*/
-var CertificatesImportError;
+let CertificatesImportError;
cr.define('certificate_manager', function() {
/** @interface */
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js
index 8bbb66fa03a..969f9126057 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js
@@ -9,7 +9,7 @@
* NOTE: This module depends on I18nBehavior which depends on loadTimeData.
*/
-var PairingEventType = chrome.bluetoothPrivate.PairingEventType;
+const PairingEventType = chrome.bluetoothPrivate.PairingEventType;
Polymer({
is: 'bluetooth-dialog',
@@ -105,9 +105,10 @@ Polymer({
close: function() {
this.endPairing();
- var dialog = this.getDialog_();
- if (dialog.open)
+ const dialog = this.getDialog_();
+ if (dialog.open) {
dialog.close();
+ }
},
/**
@@ -119,7 +120,7 @@ Polymer({
* @return {boolean}
*/
handleError: function(device, lastError, result) {
- var error;
+ let error;
if (lastError) {
error = lastError.message;
} else {
@@ -135,8 +136,8 @@ Polymer({
}
}
- var name = device.name || device.address;
- var id = 'bluetooth_connect_' + error;
+ const name = device.name || device.address;
+ const id = 'bluetooth_connect_' + error;
if (this.i18nExists(id)) {
this.errorMessage_ = this.i18n(id, name);
} else {
@@ -148,10 +149,11 @@ Polymer({
/** @private */
dialogUpdated_: function() {
- if (this.showEnterPincode_())
+ if (this.showEnterPincode_()) {
this.$$('#pincode').focus();
- else if (this.showEnterPasskey_())
+ } else if (this.showEnterPasskey_()) {
this.$$('#passkey').focus();
+ }
},
/**
@@ -169,8 +171,9 @@ Polymer({
/** @private */
onDialogCanceled_: function() {
- if (!this.errorMessage_)
+ if (!this.errorMessage_) {
this.sendResponse_(chrome.bluetoothPrivate.PairingResponse.CANCEL);
+ }
this.endPairing();
},
@@ -231,15 +234,17 @@ Polymer({
* @private
*/
onBluetoothDeviceChanged_: function(device) {
- if (!this.pairingDevice || device.address != this.pairingDevice.address)
+ if (!this.pairingDevice || device.address != this.pairingDevice.address) {
return;
+ }
this.pairingDevice = device;
},
/** @private */
pairingChanged_: function() {
- if (this.pairingDevice === undefined)
+ if (this.pairingDevice === undefined) {
return;
+ }
// Auto-close the dialog when pairing completes.
if (this.pairingDevice.paired && !this.pairingDevice.connecting &&
@@ -256,11 +261,12 @@ Polymer({
* @private
*/
getMessage_: function() {
- var message;
- if (!this.pairingEvent_)
+ let message;
+ if (!this.pairingEvent_) {
message = 'bluetoothStartConnecting';
- else
+ } else {
message = this.getEventDesc_(this.pairingEvent_.pairing);
+ }
return this.i18n(message, this.pairingDevice.name || '');
},
@@ -287,9 +293,10 @@ Polymer({
* @private
*/
showDisplayPassOrPin_: function() {
- if (!this.pairingEvent_)
+ if (!this.pairingEvent_) {
return false;
- var pairing = this.pairingEvent_.pairing;
+ }
+ const pairing = this.pairingEvent_.pairing;
return (
pairing == PairingEventType.DISPLAY_PINCODE ||
pairing == PairingEventType.DISPLAY_PASSKEY ||
@@ -311,9 +318,10 @@ Polymer({
* @private
*/
showConnect_: function() {
- if (!this.pairingEvent_)
+ if (!this.pairingEvent_) {
return false;
- var pairing = this.pairingEvent_.pairing;
+ }
+ const pairing = this.pairingEvent_.pairing;
return pairing == PairingEventType.REQUEST_PINCODE ||
pairing == PairingEventType.REQUEST_PASSKEY;
},
@@ -323,15 +331,16 @@ Polymer({
* @private
*/
enableConnect_: function() {
- if (!this.showConnect_())
+ if (!this.showConnect_()) {
return false;
- var inputId =
+ }
+ const inputId =
(this.pairingEvent_.pairing == PairingEventType.REQUEST_PINCODE) ?
'#pincode' :
'#passkey';
- var crInput = /** @type {!CrInputElement} */ (this.$$(inputId));
+ const crInput = /** @type {!CrInputElement} */ (this.$$(inputId));
assert(crInput);
- /** @type {string} */ var value = crInput.value;
+ /** @type {string} */ const value = crInput.value;
return !!value && crInput.validate();
},
@@ -365,17 +374,19 @@ Polymer({
* @private
*/
sendResponse_: function(response) {
- if (!this.pairingDevice)
+ if (!this.pairingDevice) {
return;
- var options =
+ }
+ const options =
/** @type {!chrome.bluetoothPrivate.SetPairingResponseOptions} */ (
{device: this.pairingDevice, response: response});
if (response == chrome.bluetoothPrivate.PairingResponse.CONFIRM) {
- var pairing = this.pairingEvent_.pairing;
- if (pairing == PairingEventType.REQUEST_PINCODE)
+ const pairing = this.pairingEvent_.pairing;
+ if (pairing == PairingEventType.REQUEST_PINCODE) {
options.pincode = this.$$('#pincode').value;
- else if (pairing == PairingEventType.REQUEST_PASSKEY)
+ } else if (pairing == PairingEventType.REQUEST_PASSKEY) {
options.passkey = parseInt(this.$$('#passkey').value, 10);
+ }
}
this.bluetoothPrivate.setPairingResponse(options, () => {
if (chrome.runtime.lastError) {
@@ -412,10 +423,11 @@ Polymer({
* @private
*/
getPinDigit_: function(index) {
- if (!this.pairingEvent_)
+ if (!this.pairingEvent_) {
return '';
- var digit = '0';
- var pairing = this.pairingEvent_.pairing;
+ }
+ let digit = '0';
+ const pairing = this.pairingEvent_.pairing;
if (pairing == PairingEventType.DISPLAY_PINCODE &&
this.pairingEvent_.pincode &&
index < this.pairingEvent_.pincode.length) {
@@ -425,7 +437,7 @@ Polymer({
(pairing == PairingEventType.DISPLAY_PASSKEY ||
pairing == PairingEventType.KEYS_ENTERED ||
pairing == PairingEventType.CONFIRM_PASSKEY)) {
- var passkeyString =
+ const passkeyString =
String(this.pairingEvent_.passkey).padStart(this.digits_.length, '0');
digit = passkeyString[index];
}
@@ -438,25 +450,29 @@ Polymer({
* @private
*/
getPinClass_: function(index) {
- if (!this.pairingEvent_)
+ if (!this.pairingEvent_) {
return '';
- if (this.pairingEvent_.pairing == PairingEventType.CONFIRM_PASSKEY)
+ }
+ if (this.pairingEvent_.pairing == PairingEventType.CONFIRM_PASSKEY) {
return 'confirm';
- var cssClass = 'display';
+ }
+ let cssClass = 'display';
if (this.pairingEvent_.pairing == PairingEventType.DISPLAY_PASSKEY) {
- if (index == 0)
+ if (index == 0) {
cssClass += ' next';
- else
+ } else {
cssClass += ' untyped';
+ }
} else if (
this.pairingEvent_.pairing == PairingEventType.KEYS_ENTERED &&
this.pairingEvent_.enteredKey) {
- var enteredKey = this.pairingEvent_.enteredKey; // 1-7
- var lastKey = this.digits_.length; // 6
- if ((index == -1 && enteredKey > lastKey) || (index + 1 == enteredKey))
+ const enteredKey = this.pairingEvent_.enteredKey; // 1-7
+ const lastKey = this.digits_.length; // 6
+ if ((index == -1 && enteredKey > lastKey) || (index + 1 == enteredKey)) {
cssClass += ' next';
- else if (index > enteredKey)
+ } else if (index > enteredKey) {
cssClass += ' untyped';
+ }
}
return cssClass;
},
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn
index 616ad6e48f5..838b871174e 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn
@@ -14,7 +14,6 @@ js_type_check("closure_compile") {
":multidevice_setup",
":multidevice_setup_browser_proxy",
":multidevice_setup_delegate",
- ":setup_failed_page",
":setup_succeeded_page",
":start_setup_page",
":ui_page_container_behavior",
@@ -31,12 +30,14 @@ js_library("fake_mojo_service") {
]
extra_deps = [
+ "//chromeos/components/multidevice/mojom:mojom_js",
"//chromeos/services/device_sync/public/mojom:mojom_js",
"//chromeos/services/multidevice_setup/public/mojom:mojom_js",
"//mojo/public/mojom/base:base_js",
]
externs_list = [
+ "$root_gen_dir/chromeos/components/multidevice/mojom/multidevice_types.mojom.externs.js",
"$root_gen_dir/chromeos/services/device_sync/public/mojom/device_sync.mojom.externs.js",
"$root_gen_dir/chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.externs.js",
"$root_gen_dir/mojo/public/mojom/base/time.mojom.externs.js",
@@ -57,7 +58,6 @@ js_library("multidevice_setup") {
":mojo_api",
":multidevice_setup_delegate",
":password_page",
- ":setup_failed_page",
":setup_succeeded_page",
":start_setup_page",
"//ui/webui/resources/js:cr",
@@ -65,12 +65,14 @@ js_library("multidevice_setup") {
]
extra_deps = [
+ "//chromeos/components/multidevice/mojom:mojom_js",
"//chromeos/services/device_sync/public/mojom:mojom_js",
"//chromeos/services/multidevice_setup/public/mojom:mojom_js",
"//mojo/public/mojom/base:base_js",
]
externs_list = [
+ "$root_gen_dir/chromeos/components/multidevice/mojom/multidevice_types.mojom.externs.js",
"$root_gen_dir/chromeos/services/device_sync/public/mojom/device_sync.mojom.externs.js",
"$root_gen_dir/chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.externs.js",
"$root_gen_dir/mojo/public/mojom/base/time.mojom.externs.js",
@@ -101,12 +103,6 @@ js_library("password_page") {
extra_sources = [ "$interfaces_path/quick_unlock_private_interface.js" ]
}
-js_library("setup_failed_page") {
- deps = [
- ":ui_page_container_behavior",
- ]
-}
-
js_library("setup_succeeded_page") {
deps = [
":multidevice_setup_browser_proxy",
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/OWNERS b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/OWNERS
index aef4ecb9195..d3caaf80842 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/OWNERS
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/OWNERS
@@ -1 +1,3 @@
-file://chromeos/services/multidevice_setup/OWNERS
+file://chromeos/components/multidevice/OWNERS
+
+# COMPONENT: UI>Multidevice
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.html
index 2bcb1bbc67d..770e2c00f41 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.html
@@ -1,6 +1,8 @@
<link rel="import" href="chrome://resources/html/cr.html">
<script src="chrome://resources/js/mojo_bindings.js"></script>
<script src="chrome://resources/js/time.mojom.js"></script>
+<script src="chrome://resources/js/chromeos/multidevice_types.mojom.js">
+</script>
<script src="chrome://resources/js/chromeos/device_sync.mojom.js"></script>
<script src="chrome://resources/js/chromeos/multidevice_setup.mojom.js">
</script>
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 660f1ac657f..8cce94f0cb6 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
@@ -6,7 +6,6 @@
<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/multidevice_setup_shared_css.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/password_page.html">
-<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/setup_failed_page.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/start_setup_page.html">
<link rel="import" href="chrome://resources/html/cr.html">
@@ -43,7 +42,6 @@
on-user-submitted-password="onUserSubmittedPassword_">
</password-page>
</template>
- <setup-failed-page></setup-failed-page>
<template is="dom-if"
if="[[shouldSetupSucceededPageBeIncluded_(delegate)]]" restamp>
<setup-succeeded-page></setup-succeeded-page>
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 9be02cb2a60..b49b3e7dc1c 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
@@ -6,7 +6,6 @@ cr.exportPath('multidevice_setup');
/** @enum {string} */
multidevice_setup.PageName = {
- FAILURE: 'setup-failed-page',
PASSWORD: 'password-page',
SUCCESS: 'setup-succeeded-page',
START: 'start-setup-page',
@@ -80,7 +79,7 @@ cr.define('multidevice_setup', function() {
* DOM Element corresponding to the visible page.
*
* @private {!PasswordPageElement|!StartSetupPageElement|
- * !SetupSucceededPageElement|!SetupFailedPageElement}
+ * !SetupSucceededPageElement}
*/
visiblePage_: Object,
@@ -95,7 +94,7 @@ cr.define('multidevice_setup', function() {
/**
* Array of objects representing all potential MultiDevice hosts.
*
- * @private {!Array<!chromeos.deviceSync.mojom.RemoteDevice>}
+ * @private {!Array<!chromeos.multidevice.mojom.RemoteDevice>}
*/
devices_: Array,
@@ -175,12 +174,14 @@ cr.define('multidevice_setup', function() {
/** @private */
onForwardNavigationRequested_: function() {
- if (this.forwardButtonDisabled)
+ if (this.forwardButtonDisabled) {
return;
+ }
this.visiblePage_.getCanNavigateToNextPage().then((canNavigate) => {
- if (!canNavigate)
+ if (!canNavigate) {
return;
+ }
this.navigateForward_();
});
},
@@ -188,9 +189,6 @@ cr.define('multidevice_setup', function() {
/** @private */
navigateForward_: function() {
switch (this.visiblePageName) {
- case PageName.FAILURE:
- this.visiblePageName = PageName.START;
- return;
case PageName.PASSWORD:
this.$$('password-page').clearPasswordTextInput();
this.setHostDevice_();
@@ -199,10 +197,11 @@ cr.define('multidevice_setup', function() {
this.exitSetupFlow_(true /* didUserCompleteSetup */);
return;
case PageName.START:
- if (this.delegate.isPasswordRequiredToSetHost())
+ if (this.delegate.isPasswordRequiredToSetHost()) {
this.visiblePageName = PageName.PASSWORD;
- else
+ } else {
this.setHostDevice_();
+ }
return;
}
},
@@ -244,8 +243,9 @@ cr.define('multidevice_setup', function() {
* @private
*/
getForwardButtonText_: function() {
- if (!this.visiblePage_)
+ if (!this.visiblePage_) {
return undefined;
+ }
return this.visiblePage_.forwardButtonText;
},
@@ -264,8 +264,9 @@ cr.define('multidevice_setup', function() {
* @private
*/
getCancelButtonText_: function() {
- if (!this.visiblePage_)
+ if (!this.visiblePage_) {
return undefined;
+ }
return this.visiblePage_.cancelButtonText;
},
@@ -275,8 +276,9 @@ cr.define('multidevice_setup', function() {
* @private
*/
getBackwardButtonText_: function() {
- if (!this.visiblePage_)
+ if (!this.visiblePage_) {
return undefined;
+ }
return this.visiblePage_.backwardButtonText;
},
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js
index ba2abe0bf6f..80b4f756870 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js
@@ -150,8 +150,9 @@ Polymer({
*/
onInputKeypress_: function(e) {
// We are only listening for the user trying to enter their password.
- if (e.key != 'Enter')
+ if (e.key != 'Enter') {
return;
+ }
this.fire('user-submitted-password');
},
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_failed_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_failed_page.html
deleted file mode 100644
index 181687dffd7..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_failed_page.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/ui_page.html">
-<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-
-<dom-module id="setup-failed-page">
- <template>
- <ui-page header-text="[[headerText]]" icon-name="error-icon">
- <span slot="message" inner-h-t-m-l="[[messageHtml]]"></span>
- <div slot="additional-content">
- This is empty... (PlAcEhOlDeR tExT!!)
- </div>
- </ui-page>
- </template>
- <script src="chrome://resources/cr_components/chromeos/multidevice_setup/setup_failed_page.js">
- </script>
-</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_failed_page.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_failed_page.js
deleted file mode 100644
index 36f2d4ae117..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_failed_page.js
+++ /dev/null
@@ -1,43 +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.
-
-Polymer({
- is: 'setup-failed-page',
-
- properties: {
- /** Overridden from UiPageContainerBehavior. */
- forwardButtonTextId: {
- type: String,
- value: 'tryAgain',
- },
-
- /** Overridden from UiPageContainerBehavior. */
- cancelButtonTextId: {
- type: String,
- value: 'cancel',
- },
-
- /** Overridden from UiPageContainerBehavior. */
- backwardButtonTextId: {
- type: String,
- value: 'back',
- },
-
- /** Overridden from UiPageContainerBehavior. */
- headerId: {
- type: String,
- value: 'setupFailedPageHeader',
- },
-
- /** Overridden from UiPageContainerBehavior. */
- messageId: {
- type: String,
- value: 'setupFailedPageMessage',
- },
- },
-
- behaviors: [
- UiPageContainerBehavior,
- ],
-});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js
index d9f6db488e7..f5445d942e0 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js
@@ -33,7 +33,7 @@ Polymer({
/**
* Array of objects representing all potential MultiDevice hosts.
*
- * @type {!Array<!chromeos.deviceSync.mojom.RemoteDevice>}
+ * @type {!Array<!chromeos.multidevice.mojom.RemoteDevice>}
*/
devices: {
type: Array,
@@ -99,7 +99,7 @@ Polymer({
},
/**
- * @param {!Array<!chromeos.deviceSync.mojom.RemoteDevice>} devices
+ * @param {!Array<!chromeos.multidevice.mojom.RemoteDevice>} devices
* @return {string} Label for devices selection content.
* @private
*/
@@ -115,7 +115,7 @@ Polymer({
},
/**
- * @param {!Array<!chromeos.deviceSync.mojom.RemoteDevice>} devices
+ * @param {!Array<!chromeos.multidevice.mojom.RemoteDevice>} devices
* @return {boolean} True if there are more than one potential host devices.
* @private
*/
@@ -124,7 +124,7 @@ Polymer({
},
/**
- * @param {!Array<!chromeos.deviceSync.mojom.RemoteDevice>} devices
+ * @param {!Array<!chromeos.multidevice.mojom.RemoteDevice>} devices
* @return {boolean} True if there is exactly one potential host device.
* @private
*/
@@ -133,7 +133,7 @@ Polymer({
},
/**
- * @param {!Array<!chromeos.deviceSync.mojom.RemoteDevice>} devices
+ * @param {!Array<!chromeos.multidevice.mojom.RemoteDevice>} devices
* @return {string} Name of the first device in device list if there are any.
* Returns an empty string otherwise.
* @private
@@ -144,8 +144,9 @@ Polymer({
/** @private */
devicesChanged_: function() {
- if (this.devices.length > 0)
+ if (this.devices.length > 0) {
this.selectedDeviceId = this.devices[0].deviceId;
+ }
},
/** @private */
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js
index e9f16b9ee89..cb31b5170dc 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js
@@ -127,8 +127,9 @@ const UiPageContainerBehaviorImpl = {
* @private
*/
computeLocalizedText_: function(textId) {
- if (!this.i18nExists(textId))
+ if (!this.i18nExists(textId)) {
return;
+ }
return loadTimeData.getString(textId);
},
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 538ab5b2865..687dd545566 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
@@ -88,8 +88,9 @@ Polymer({
* Polymer networkProperties changed method.
*/
networkPropertiesChanged_: function() {
- if (!this.networkProperties || !this.networkProperties.Cellular)
+ if (!this.networkProperties || !this.networkProperties.Cellular) {
return;
+ }
/** @type {!CrOnc.APNProperties|undefined} */ let activeApn;
const cellular = this.networkProperties.Cellular;
@@ -156,8 +157,9 @@ Polymer({
*/
createApnObject_: function(apnProperties) {
const newApn = {AccessPointName: ''};
- if (apnProperties)
+ if (apnProperties) {
Object.assign(newApn, apnProperties);
+ }
return newApn;
},
@@ -167,12 +169,14 @@ Polymer({
* @private
*/
getApnList_: function() {
- if (!this.networkProperties || !this.networkProperties.Cellular)
+ if (!this.networkProperties || !this.networkProperties.Cellular) {
return [];
+ }
/** @type {!chrome.networkingPrivate.ManagedAPNList|undefined} */
const apnlist = this.networkProperties.Cellular.APNList;
- if (!apnlist)
+ if (!apnlist) {
return [];
+ }
return /** @type {!Array<!CrOnc.APNProperties>} */ (
CrOnc.getActiveValue(apnlist));
},
@@ -245,8 +249,9 @@ Polymer({
* @private
*/
isOtherSelected_: function(accessPointName) {
- if (!this.networkProperties || !this.networkProperties.Cellular)
+ if (!this.networkProperties || !this.networkProperties.Cellular) {
return false;
+ }
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 b6126963195..28abe3dae07 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
@@ -64,8 +64,9 @@ Polymer({
* Polymer networkProperties changed method.
*/
networkPropertiesChanged_: function() {
- if (!this.networkProperties || !this.networkProperties.Cellular)
+ if (!this.networkProperties || !this.networkProperties.Cellular) {
return;
+ }
const cellular = this.networkProperties.Cellular;
this.mobileNetworkList_ = cellular.FoundNetworks ||
[{NetworkId: 'none', LongName: this.i18n('networkCellularNoNetworks')}];
@@ -75,8 +76,9 @@ Polymer({
let selected = this.mobileNetworkList_.find(function(mobileNetwork) {
return mobileNetwork.Status == 'current';
});
- if (!selected)
+ if (!selected) {
selected = this.mobileNetworkList_[0];
+ }
this.selectedMobileNetworkId_ = selected.NetworkId;
});
},
@@ -120,15 +122,18 @@ Polymer({
* @private
*/
getSecondaryText_: function(properties) {
- if (!properties || !properties.Cellular)
+ if (!properties || !properties.Cellular) {
return '';
+ }
const cellular = properties.Cellular;
- if (cellular.Scanning)
+ if (cellular.Scanning) {
return this.i18n('networkCellularScanning');
- else if (this.scanRequested_)
+ } else if (this.scanRequested_) {
return this.i18n('networkCellularScanCompleted');
- else if (properties.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED)
+ } else if (
+ properties.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED) {
return this.i18n('networkCellularScanConnectedHelp');
+ }
return '';
},
@@ -158,8 +163,9 @@ Polymer({
*/
onChange_: function(event) {
const target = /** @type {!HTMLSelectElement} */ (event.target);
- if (!target.value || target.value == 'none')
+ if (!target.value || target.value == 'none') {
return;
+ }
this.networkingPrivate.selectCellularMobileNetwork(
this.networkProperties.GUID, target.value);
},
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 78ca586d781..793f97239b7 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
@@ -387,8 +387,9 @@ Polymer({
* @private
*/
saveAndConnect_: function(connect) {
- if (this.propertiesSent_)
+ if (this.propertiesSent_) {
return;
+ }
this.propertiesSent_ = true;
this.error = '';
@@ -420,14 +421,16 @@ Polymer({
'network-config-input:not([readonly]),' +
'network-password-input:not([disabled]),' +
'network-config-select:not([disabled])');
- if (e)
+ if (e) {
e.focus();
+ }
},
/** @private */
connectIfConfigured_: function() {
- if (!this.isConfigured_)
+ if (!this.isConfigured_) {
return;
+ }
this.connect();
},
@@ -450,8 +453,9 @@ Polymer({
* @return {!CrOnc.Source}
*/
getSource_: function() {
- if (!this.guid)
+ if (!this.guid) {
return CrOnc.Source.NONE;
+ }
const source = this.managedProperties.Source;
return source ? /** @type {!CrOnc.Source} */ (source) : CrOnc.Source.NONE;
},
@@ -477,8 +481,9 @@ Polymer({
let userCerts = certificateLists.userCertificates.slice();
// Only hardware backed user certs are supported.
userCerts.forEach(function(cert) {
- if (!cert.hardwareBacked)
- cert.hash = ''; // Clear the hash to invalidate the certificate.
+ if (!cert.hardwareBacked) {
+ cert.hash = '';
+ } // Clear the hash to invalidate the certificate.
});
if (isOpenVpn) {
// OpenVPN allows but does not require a user certificate.
@@ -755,10 +760,12 @@ Polymer({
}
this.configProperties_ = configProperties;
this.set('eapProperties_', this.getEap_(this.configProperties_));
- if (!this.eapProperties_)
+ if (!this.eapProperties_) {
this.showEap_ = null;
- if (managedProperties.Type == CrOnc.Type.VPN)
+ }
+ if (managedProperties.Type == CrOnc.Type.VPN) {
this.vpnType_ = this.getVpnTypeFromProperties_(this.configProperties_);
+ }
},
/**
@@ -793,12 +800,14 @@ Polymer({
*/
updateEapOuter_: function() {
const eap = this.eapProperties_;
- if (!eap || !eap.Outer)
+ if (!eap || !eap.Outer) {
return;
+ }
const innerItems = this.getEapInnerItems_(eap.Outer);
if (innerItems.length > 0) {
- if (!eap.Inner || innerItems.indexOf(eap.Inner) < 0)
+ if (!eap.Inner || innerItems.indexOf(eap.Inner) < 0) {
this.set('eapProperties_.Inner', innerItems[0]);
+ }
} else {
this.set('eapProperties_.Inner', undefined);
}
@@ -809,8 +818,9 @@ Polymer({
/** @private */
updateEapCerts_: function() {
// EAP is used for all configurable types except VPN.
- if (this.type == CrOnc.Type.VPN)
+ if (this.type == CrOnc.Type.VPN) {
return;
+ }
const eap = this.eapProperties_;
const pem = eap && eap.ServerCAPEMs ? eap.ServerCAPEMs[0] : '';
const certId =
@@ -870,10 +880,12 @@ Polymer({
eap = properties.WiMAX && properties.WiMAX.EAP;
break;
}
- if (opt_create)
+ if (opt_create) {
return eap || {};
- if (eap)
+ }
+ if (eap) {
eap.SaveCredentials = eap.SaveCredentials || false;
+ }
return eap || null;
},
@@ -936,8 +948,9 @@ Polymer({
/** @private */
updateVpnType_: function() {
- if (this.configProperties_ === undefined)
+ if (this.configProperties_ === undefined) {
return;
+ }
const vpn = this.configProperties_.VPN;
if (!vpn) {
@@ -948,18 +961,20 @@ Polymer({
switch (this.vpnType_) {
case VPNConfigType.L2TP_IPSEC_PSK:
vpn.Type = CrOnc.VPNType.L2TP_IPSEC;
- if (vpn.IPsec)
+ if (vpn.IPsec) {
vpn.IPsec.AuthenticationType = CrOnc.IPsecAuthenticationType.PSK;
- else
+ } else {
vpn.IPsec = {AuthenticationType: CrOnc.IPsecAuthenticationType.PSK};
+ }
this.showVpn_ = {Cert: false, OpenVPN: false};
break;
case VPNConfigType.L2TP_IPSEC_CERT:
vpn.Type = CrOnc.VPNType.L2TP_IPSEC;
- if (vpn.IPsec)
+ if (vpn.IPsec) {
vpn.IPsec.AuthenticationType = CrOnc.IPsecAuthenticationType.CERT;
- else
+ } else {
vpn.IPsec = {AuthenticationType: CrOnc.IPsecAuthenticationType.CERT};
+ }
this.showVpn_ = {Cert: true, OpenVPN: false};
break;
case VPNConfigType.OPEN_VPN:
@@ -974,8 +989,9 @@ Polymer({
/** @private */
updateVpnIPsecCerts_: function() {
- if (this.vpnType_ != VPNConfigType.L2TP_IPSEC_CERT)
+ if (this.vpnType_ != VPNConfigType.L2TP_IPSEC_CERT) {
return;
+ }
let pem, certId;
const ipsec = /** @type {chrome.networkingPrivate.IPSecProperties} */ (
this.get('VPN.IPsec', this.configProperties_));
@@ -989,8 +1005,9 @@ Polymer({
/** @private */
updateOpenVPNCerts_: function() {
- if (this.vpnType_ != VPNConfigType.OPEN_VPN)
+ if (this.vpnType_ != VPNConfigType.OPEN_VPN) {
return;
+ }
let pem, certId;
const openvpn = /** @type {chrome.networkingPrivate.OpenVPNProperties} */ (
this.get('VPN.OpenVPN', this.configProperties_));
@@ -1047,16 +1064,22 @@ Polymer({
const serverCa = this.serverCaCerts_.find(function(cert) {
return cert.pem == pem;
});
- if (serverCa)
+ if (serverCa) {
this.selectedServerCaHash_ = serverCa.hash;
+ }
}
if (certId) {
+ // |certId| is in the format |slot:id| for EAP and IPSec and |id| for
+ // OpenVPN certs.
+ // |userCerts_[i].PKCS11Id| is always in the format |slot:id|.
+ // Use a substring comparison to support both |certId| formats.
const userCert = this.userCerts_.find(function(cert) {
- return cert.PKCS11Id == certId;
+ return cert.PKCS11Id.indexOf(/** @type {string} */ (certId)) >= 0;
});
- if (userCert)
+ if (userCert) {
this.selectedUserCertHash_ = userCert.hash;
+ }
}
this.updateSelectedCerts_();
this.updateIsConfigured_();
@@ -1069,8 +1092,9 @@ Polymer({
* @return {!chrome.networkingPrivate.Certificate|undefined}
*/
findCert_: function(certs, hash) {
- if (!hash)
+ if (!hash) {
return undefined;
+ }
return certs.find((cert) => {
return cert.hash == hash;
});
@@ -1083,21 +1107,31 @@ Polymer({
* @private
*/
updateSelectedCerts_: function() {
- if (!this.findCert_(this.serverCaCerts_, this.selectedServerCaHash_))
+ if (!this.findCert_(this.serverCaCerts_, this.selectedServerCaHash_)) {
this.selectedServerCaHash_ = undefined;
+ }
if (!this.selectedServerCaHash_ ||
this.selectedServerCaHash_ == DEFAULT_HASH) {
const eap = this.eapProperties_;
- if (eap && eap.UseSystemCAs === false)
+ if (eap && eap.UseSystemCAs === false) {
+ this.selectedServerCaHash_ = DO_NOT_CHECK_HASH;
+ }
+ }
+ if (!this.selectedServerCaHash_) {
+ // For unconfigured networks only, default to the first CA if available.
+ if (!this.guid && this.serverCaCerts_[0]) {
+ this.selectedServerCaHash_ = this.serverCaCerts_[0].hash;
+ } else {
this.selectedServerCaHash_ = DO_NOT_CHECK_HASH;
+ }
}
- if (!this.selectedServerCaHash_ && this.serverCaCerts_[0])
- this.selectedServerCaHash_ = this.serverCaCerts_[0].hash;
- if (!this.findCert_(this.userCerts_, this.selectedUserCertHash_))
+ if (!this.findCert_(this.userCerts_, this.selectedUserCertHash_)) {
this.selectedUserCertHash_ = undefined;
- if (!this.selectedUserCertHash_ && this.userCerts_[0])
+ }
+ if (!this.selectedUserCertHash_ && this.userCerts_[0]) {
this.selectedUserCertHash_ = this.userCerts_[0].hash;
+ }
},
/**
@@ -1105,23 +1139,28 @@ Polymer({
* @private
*/
getIsConfigured_: function() {
- if (!this.configProperties_)
+ if (!this.configProperties_) {
return false;
+ }
- if (this.configProperties_.Type == CrOnc.Type.VPN)
+ if (this.configProperties_.Type == CrOnc.Type.VPN) {
return this.vpnIsConfigured_();
+ }
if (this.type == CrOnc.Type.WI_FI) {
- if (!this.get('WiFi.SSID', this.configProperties_))
+ if (!this.get('WiFi.SSID', this.configProperties_)) {
return false;
+ }
if (this.configRequiresPassphrase_()) {
const passphrase = this.get('WiFi.Passphrase', this.configProperties_);
- if (!passphrase || passphrase.length < this.MIN_PASSPHRASE_LENGTH)
+ if (!passphrase || passphrase.length < this.MIN_PASSPHRASE_LENGTH) {
return false;
+ }
}
}
- if (this.security_ == CrOnc.Security.WPA_EAP)
+ if (this.security_ == CrOnc.Security.WPA_EAP) {
return this.eapIsConfigured_();
+ }
return true;
},
@@ -1205,19 +1244,22 @@ Polymer({
* @private
*/
shareIsEnabled_: function() {
- if (!this.shareAllowEnable || this.getSource_() != CrOnc.Source.NONE)
+ if (!this.shareAllowEnable || this.getSource_() != CrOnc.Source.NONE) {
return false;
+ }
if (this.security_ == CrOnc.Security.WPA_EAP) {
const eap = this.getEap_(this.configProperties_);
- if (eap && eap.Outer == CrOnc.EAPType.EAP_TLS)
+ if (eap && eap.Outer == CrOnc.EAPType.EAP_TLS) {
return false;
+ }
}
if (this.type == CrOnc.Type.WI_FI) {
// Insecure WiFi networks are always shared.
- if (this.security_ == CrOnc.Security.NONE)
+ if (this.security_ == CrOnc.Security.NONE) {
return false;
+ }
}
return true;
},
@@ -1237,10 +1279,12 @@ Polymer({
*/
eapIsConfigured_: function() {
const eap = this.getEap_(this.configProperties_);
- if (!eap)
+ if (!eap) {
return false;
- if (eap.Outer != CrOnc.EAPType.EAP_TLS)
+ }
+ if (eap.Outer != CrOnc.EAPType.EAP_TLS) {
return true;
+ }
return this.selectedUserCertHashIsValid_();
},
@@ -1250,8 +1294,9 @@ Polymer({
*/
vpnIsConfigured_: function() {
const vpn = this.configProperties_.VPN;
- if (!this.configProperties_.Name || !vpn || !vpn.Host)
+ if (!this.configProperties_.Name || !vpn || !vpn.Host) {
return false;
+ }
switch (this.vpnType_) {
case VPNConfigType.L2TP_IPSEC_PSK:
@@ -1274,16 +1319,24 @@ Polymer({
// 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)
+ if (this.guid) {
propertiesToSet.GUID = this.guid;
+ }
const eap = this.getEap_(propertiesToSet);
- if (eap)
+ if (eap) {
this.setEapProperties_(eap);
+ }
if (this.configProperties_.Type == CrOnc.Type.VPN) {
- if (this.get('VPN.Type', propertiesToSet) == CrOnc.VPNType.OPEN_VPN)
+ // VPN.Host can be an IP address but will not be recognized as such if
+ // there is initial whitespace, so trim it.
+ if (typeof propertiesToSet.VPN.Host == 'string') {
+ propertiesToSet.VPN.Host = propertiesToSet.VPN.Host.trim();
+ }
+ if (this.get('VPN.Type', propertiesToSet) == CrOnc.VPNType.OPEN_VPN) {
this.setOpenVPNProperties_(propertiesToSet);
- else
+ } else {
this.setVpnIPsecProperties_(propertiesToSet);
+ }
}
return propertiesToSet;
},
@@ -1294,8 +1347,9 @@ Polymer({
*/
getServerCaPems_: function() {
const caHash = this.selectedServerCaHash_ || '';
- if (!caHash || caHash == DO_NOT_CHECK_HASH || caHash == DEFAULT_HASH)
+ if (!caHash || caHash == DO_NOT_CHECK_HASH || caHash == DEFAULT_HASH) {
return [];
+ }
const serverCa = this.findCert_(this.serverCaCerts_, caHash);
return serverCa && serverCa.pem ? [serverCa.pem] : [];
},
@@ -1415,8 +1469,9 @@ Polymer({
this.propertiesSent_ = false;
return;
}
- if (connect)
+ if (connect) {
this.startConnect_(guid);
+ }
},
/**
@@ -1456,10 +1511,12 @@ Polymer({
* @private
*/
getEapInnerItems_: function(outer) {
- if (outer == CrOnc.EAPType.PEAP)
+ if (outer == CrOnc.EAPType.PEAP) {
return this.eapInnerItemsPeap_;
- if (outer == CrOnc.EAPType.EAP_TTLS)
+ }
+ if (outer == CrOnc.EAPType.EAP_TTLS) {
return this.eapInnerItemsTtls_;
+ }
return [];
},
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 6bf3e829c95..c315528efda 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
@@ -53,8 +53,9 @@ Polymer({
// Wait for the dom-repeat to populate the <option> entries.
this.async(function() {
const select = this.$$('select');
- if (select.value != this.value)
+ if (select.value != this.value) {
select.value = this.value;
+ }
});
},
@@ -71,8 +72,9 @@ Polymer({
}
const key = /** @type {string} */ (item);
const oncKey = 'Onc' + prefix.replace(/\./g, '-') + '_' + key;
- if (this.i18nExists(oncKey))
+ if (this.i18nExists(oncKey)) {
return this.i18n(oncKey);
+ }
assertNotReached('ONC Key not found: ' + oncKey);
return key;
},
@@ -83,8 +85,9 @@ Polymer({
* @private
*/
getItemValue_: function(item) {
- if (this.certList)
+ if (this.certList) {
return /** @type {chrome.networkingPrivate.Certificate}*/ (item).hash;
+ }
return /** @type {string} */ (item);
},
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html
index f3a3ca1944e..abca58c96f8 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html
@@ -2,18 +2,28 @@
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.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_indicator.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="network_property_list.html">
<link rel="import" href="network_shared_css.html">
<dom-module id="network-ip-config">
<template>
- <style include="network-shared iron-flex"></style>
+ <style include="network-shared iron-flex">
+ cr-toggle {
+ margin-inline-start: var(--settings-control-label-spacing);
+ }
+ </style>
<div class="property-box">
<div id="autoIPConfigLabel" class="start">
[[i18n('networkIPConfigAuto')]]
</div>
- <cr-toggle checked="{{automatic_}}" disabled="[[!editable]]"
+ <cr-policy-indicator indicator-type="[[getPolicyIndicatorType_(
+ networkProperties, 'IPAddressConfigType')]]">
+ </cr-policy-indicator>
+ <cr-toggle checked="{{automatic_}}"
+ disabled="[[!canChangeIPConfigType_(editable, networkProperties)]]"
on-change="onAutomaticChange_"
aria-labelledby="autoIPConfigLabel">
</cr-toggle>
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 7f3cb3dd6ec..dea3b183e3b 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
@@ -10,7 +10,7 @@
Polymer({
is: 'network-ip-config',
- behaviors: [I18nBehavior],
+ behaviors: [I18nBehavior, CrPolicyNetworkBehavior],
properties: {
/**
@@ -78,12 +78,14 @@ Polymer({
* Polymer networkProperties changed method.
*/
networkPropertiesChanged_: function(newValue, oldValue) {
- if (!this.networkProperties)
+ if (!this.networkProperties) {
return;
+ }
const properties = this.networkProperties;
- if (newValue.GUID != (oldValue && oldValue.GUID))
+ if (newValue.GUID != (oldValue && oldValue.GUID)) {
this.savedStaticIp_ = undefined;
+ }
// Update the 'automatic' property.
if (properties.IPAddressConfigType) {
@@ -108,6 +110,28 @@ Polymer({
}
},
+ /**
+ * Checks whether IP address config type can be changed.
+ * @param {boolean} editable
+ * @param {!CrOnc.NetworkProperties} networkProperties
+ * @return {boolean} true only if 'IPAddressConfigType' as well as all other
+ * IP address config related fields are editable.
+ * @private
+ */
+ canChangeIPConfigType_: function(editable, networkProperties) {
+ if (!editable) {
+ return false;
+ }
+ const controlledProps = [
+ 'IPAddressConfigType', 'StaticIPConfig.IPAddress',
+ 'StaticIPConfig.RoutingPrefix', 'StaticIPConfig.Gateway'
+ ];
+
+ return controlledProps.every(
+ setting =>
+ !this.isNetworkPolicyPathEnforced(networkProperties, setting));
+ },
+
/** @private */
onAutomaticChange_: function() {
if (!this.automatic_) {
@@ -119,17 +143,19 @@ Polymer({
};
// Ensure that there is a valid IPConfig object. Copy any set properties
// over the default properties to ensure all properties are set.
- if (this.ipConfig_)
+ if (this.ipConfig_) {
this.ipConfig_.ipv4 = Object.assign(defaultIpv4, this.ipConfig_.ipv4);
- else
+ } else {
this.ipConfig_ = {ipv4: defaultIpv4};
+ }
this.sendStaticIpConfig_();
return;
}
// Save the static IP configuration when switching to automatic.
- if (this.ipConfig_)
+ if (this.ipConfig_) {
this.savedStaticIp_ = this.ipConfig_.ipv4;
+ }
// Send the change.
this.fire('ip-change', {
field: 'IPAddressConfigType',
@@ -145,15 +171,17 @@ Polymer({
* @private
*/
getIPConfigUIProperties_: function(ipconfig) {
- if (!ipconfig)
+ if (!ipconfig) {
return undefined;
+ }
const result = {};
for (const key in ipconfig) {
const value = ipconfig[key];
- if (key == 'RoutingPrefix')
+ if (key == 'RoutingPrefix') {
result.RoutingPrefix = CrOnc.getRoutingPrefixAsNetmask(value);
- else
+ } else {
result[key] = value;
+ }
}
return result;
},
@@ -168,10 +196,11 @@ Polymer({
const result = {};
for (const key in ipconfig) {
const value = ipconfig[key];
- if (key == 'RoutingPrefix')
+ if (key == 'RoutingPrefix') {
result.RoutingPrefix = CrOnc.getRoutingPrefixAsLength(value);
- else
+ } else {
result[key] = value;
+ }
}
return result;
},
@@ -181,11 +210,13 @@ Polymer({
* @private
*/
hasIpConfigFields_: function() {
- if (!this.ipConfigFields_)
+ if (!this.ipConfigFields_) {
return false;
+ }
for (let i = 0; i < this.ipConfigFields_.length; ++i) {
- if (this.get(this.ipConfigFields_[i], this.ipConfig_) != undefined)
+ if (this.get(this.ipConfigFields_[i], this.ipConfig_) != undefined) {
return true;
+ }
}
return false;
},
@@ -195,8 +226,9 @@ Polymer({
* @private
*/
getIPEditFields_: function() {
- if (!this.editable || this.automatic_)
+ if (!this.editable || this.automatic_) {
return {};
+ }
return {
'ipv4.IPAddress': 'String',
'ipv4.RoutingPrefix': 'String',
@@ -211,8 +243,9 @@ Polymer({
* @private
*/
onIPChange_: function(event) {
- if (!this.ipConfig_)
+ if (!this.ipConfig_) {
return;
+ }
const field = event.detail.field;
const value = event.detail.value;
// Note: |field| includes the 'ipv4.' prefix.
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 a38f89212e4..5b0a1a77994 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
@@ -4,6 +4,8 @@
<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/cr_elements/policy/cr_policy_indicator.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.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">
@@ -32,6 +34,10 @@
margin-inline-start: 38px;
}
+ .nameservers:not([changeable]) {
+ opacity: var(--cr-disabled-opacity);
+ }
+
#radioGroupDiv {
align-items: center;
display: block;
@@ -39,28 +45,38 @@
padding-inline-start: var(--cr-section-padding);
}
+ cr-policy-indicator {
+ /* Aligns with the other policy indicators. */
+ margin-inline-end: calc(var(--settings-control-label-spacing) + 34px);
+ }
</style>
<div class="property-box">
- [[i18n('networkNameservers')]]
+ <div class="start">
+ [[i18n('networkNameservers')]]
+ </div>
+ <cr-policy-indicator indicator-type="[[getPolicyIndicatorType_(
+ networkProperties, 'NameServersConfigType')]]">
+ </cr-policy-indicator>
</div>
-
<div id="radioGroupDiv">
<cr-radio-group id="nameserverType" class="layout vertical"
selected="[[nameserversType_]]"
on-selected-changed="onTypeChange_"
aria-label="[[i18n('networkNameservers')]]">
<!-- Automatic nameservers -->
- <cr-radio-button name="automatic">
+ <cr-radio-button name="automatic" disabled="[[!canChangeConfigType_]]">
[[i18n('networkNameserversAutomatic')]]
</cr-radio-button>
<template is="dom-if" if="[[showNameservers_(nameserversType_,
'automatic', nameservers_)]]">
- <div class="nameservers">[[getNameserversString_(nameservers_)]]</div>
+ <div class="nameservers" changeable$="[[canChangeConfigType_]]">
+ [[getNameserversString_(nameservers_)]]
+ </div>
</template>
<!-- Google nameservers -->
- <cr-radio-button name="google">
+ <cr-radio-button name="google" disabled="[[!canChangeConfigType_]]">
[[i18n('networkNameserversGoogle')]]
<template is="dom-if"
if="[[i18nExists('networkGoogleNameserversLearnMoreUrl')]]">
@@ -72,11 +88,13 @@
</cr-radio-button>
<template is="dom-if" if="[[showNameservers_(nameserversType_,
'google', nameservers_)]]">
- <div class="nameservers">[[getNameserversString_(nameservers_)]]</div>
+ <div class$="nameservers">
+ [[getNameserversString_(nameservers_)]]
+ </div>
</template>
<!-- Custom nameservers -->
- <cr-radio-button name="custom">
+ <cr-radio-button name="custom" disabled="[[!canChangeConfigType_]]">
[[i18n('networkNameserversCustom')]]
</cr-radio-button>
<template is="dom-if" if="[[showNameservers_(nameserversType_,
@@ -85,7 +103,8 @@
<template is="dom-repeat" items="[[nameservers_]]">
<cr-input id="nameserver[[index]]" value="[[item]]"
on-change="onValueChange_"
- disabled="[[!canEdit_(editable, nameserversType_)]]">
+ disabled="[[!canEditCustomNameServers_(editable,
+ nameserversType_, networkProperties)]]">
</cr-input>
</template>
</div>
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 e1cf0a478a0..d408778616c 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
@@ -8,7 +8,7 @@
Polymer({
is: 'network-nameservers',
- behaviors: [I18nBehavior],
+ behaviors: [I18nBehavior, CrPolicyNetworkBehavior],
properties: {
/**
@@ -54,6 +54,12 @@ Polymer({
return this.i18nAdvanced(
'networkNameserversGoogle', {substitutions: [], tags: ['a']});
}
+ },
+
+ /** @private */
+ canChangeConfigType_: {
+ type: Boolean,
+ computed: 'computeCanChangeConfigType_(editable, networkProperties)',
}
},
@@ -74,18 +80,21 @@ Polymer({
/** @private */
networkPropertiesChanged_: function(newValue, oldValue) {
- if (!this.networkProperties)
+ if (!this.networkProperties) {
return;
+ }
- if (!oldValue || newValue.GUID != oldValue.GUID)
+ if (!oldValue || newValue.GUID != oldValue.GUID) {
this.savedNameservers_ = [];
+ }
// Update the 'nameservers' property.
let nameservers = [];
const ipv4 =
CrOnc.getIPConfigForType(this.networkProperties, CrOnc.IPType.IPV4);
- if (ipv4 && ipv4.NameServers)
+ if (ipv4 && ipv4.NameServers) {
nameservers = ipv4.NameServers;
+ }
// Update the 'nameserversType' property.
const configType =
@@ -114,27 +123,53 @@ Polymer({
setNameservers_: function(nameserversType, nameservers, sendNameservers) {
if (nameserversType == 'custom') {
// Add empty entries for unset custom nameservers.
- for (let i = nameservers.length; i < this.MAX_NAMESERVERS; ++i)
+ for (let i = nameservers.length; i < this.MAX_NAMESERVERS; ++i) {
nameservers[i] = '';
+ }
this.savedNameservers_ = nameservers.slice();
}
this.nameservers_ = nameservers;
// Set nameserversType_ after dom-repeat has been stamped.
this.async(() => {
this.nameserversType_ = nameserversType;
- if (sendNameservers)
+ if (sendNameservers) {
this.sendNameServers_();
+ }
});
},
/**
* @param {boolean} editable
+ * @param {!CrOnc.NetworkProperties} networkProperties
+ * @return {boolean} True if the nameservers config type type can be changed.
+ * @private
+ */
+ computeCanChangeConfigType_: function(editable, networkProperties) {
+ if (!editable) {
+ return false;
+ }
+
+ return !this.isNetworkPolicyPathEnforced(
+ networkProperties, 'NameServersConfigType') &&
+ !this.isNetworkPolicyPathEnforced(
+ networkProperties, 'StaticIPConfig.NameServers');
+ },
+
+ /**
+ * @param {boolean} editable
* @param {string} nameserversType
+ * @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean} True if the nameservers are editable.
* @private
*/
- canEdit_: function(editable, nameserversType) {
- return editable && nameserversType == 'custom';
+ canEditCustomNameServers_: function(
+ editable, nameserversType, networkProperties) {
+ return editable && nameserversType == 'custom' &&
+ !this.isNetworkPolicyEnforced(
+ networkProperties.NameServersConfigType) &&
+ !!networkProperties.StaticIPConfig &&
+ !this.isNetworkPolicyEnforced(
+ networkProperties.StaticIPConfig.NameServers);
},
/**
@@ -145,8 +180,9 @@ Polymer({
* @private
*/
showNameservers_: function(nameserversType, type, nameservers) {
- if (nameserversType != type)
+ if (nameserversType != type) {
return false;
+ }
return type == 'custom' || nameservers.length > 0;
},
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 fda9d28de7a..647cf6ab264 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
@@ -55,8 +55,9 @@ Polymer({
/** @private */
updateShowPassword_: function() {
- if (this.value == FAKE_CREDENTIAL)
+ if (this.value == FAKE_CREDENTIAL) {
this.showPassword = false;
+ }
},
focus: function() {
@@ -113,8 +114,9 @@ Polymer({
* @private
*/
onKeypress_: function(event) {
- if (event.target.id != 'input' || event.key != 'Enter')
+ if (event.target.id != 'input' || event.key != 'Enter') {
return;
+ }
event.stopPropagation();
this.fire('enter');
},
@@ -126,8 +128,9 @@ Polymer({
* @private
*/
onFocus_: function(e) {
- if (this.value != FAKE_CREDENTIAL)
+ 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 = '';
@@ -144,8 +147,9 @@ Polymer({
* @private
*/
onBlur_: function(e) {
- if (!this.restoreUnknown_)
+ 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;
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 42629e96f16..00f9ae3f42d 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
@@ -73,8 +73,9 @@ Polymer({
* @private
*/
onValueChange_: function(event) {
- if (!this.propertyDict)
+ if (!this.propertyDict) {
return;
+ }
const key = event.target.id;
let curValue = this.get(key, this.propertyDict);
if (typeof curValue == 'object' && !Array.isArray(curValue)) {
@@ -83,8 +84,9 @@ Polymer({
/** @type {!CrOnc.ManagedProperty} */ (curValue));
}
const newValue = this.getValueFromEditField_(key, event.target.value);
- if (newValue == curValue)
+ if (newValue == curValue) {
return;
+ }
this.fire('property-change', {field: key, value: newValue});
},
@@ -97,8 +99,9 @@ Polymer({
getPropertyLabel_: function(key, prefix) {
let oncKey = 'Onc' + prefix + key;
oncKey = oncKey.replace(/\./g, '-');
- if (this.i18nExists(oncKey))
+ 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.
let result = prefix + key;
@@ -121,8 +124,9 @@ Polymer({
*/
computeFilter_: function(prefix, propertyDict, editFieldTypes) {
return key => {
- if (editFieldTypes.hasOwnProperty(key))
+ if (editFieldTypes.hasOwnProperty(key)) {
return true;
+ }
const value = this.getPropertyValue_(key, prefix, propertyDict);
return value !== undefined && value !== '';
};
@@ -216,29 +220,34 @@ Polymer({
*/
getPropertyValue_: function(key, prefix, propertyDict) {
let value = this.get(key, propertyDict);
- if (value === undefined)
+ if (value === undefined) {
return '';
+ }
if (typeof value == 'object' && !Array.isArray(value)) {
// Extract the property from an ONC managed dictionary
value =
CrOnc.getActiveValue(/** @type {!CrOnc.ManagedProperty} */ (value));
}
- if (Array.isArray(value))
+ if (Array.isArray(value)) {
return value.join(', ');
+ }
const customValue = this.getCustomPropertyValue_(key, value);
- if (customValue)
+ if (customValue) {
return customValue;
- if (typeof value == 'number' || typeof value == 'boolean')
+ }
+ if (typeof value == 'number' || typeof value == 'boolean') {
return value.toString();
+ }
assert(typeof value == 'string');
const valueStr = /** @type {string} */ (value);
let oncKey = 'Onc' + prefix + key;
oncKey = oncKey.replace(/\./g, '-');
oncKey += '_' + valueStr;
- if (this.i18nExists(oncKey))
+ if (this.i18nExists(oncKey)) {
return this.i18n(oncKey);
+ }
return valueStr;
},
@@ -251,8 +260,9 @@ Polymer({
*/
getValueFromEditField_(key, fieldValue) {
const editType = this.editFieldTypes[key];
- if (editType == 'StringArray')
+ if (editType == 'StringArray') {
return fieldValue.toString().split(/, */);
+ }
return fieldValue;
},
@@ -272,14 +282,18 @@ Polymer({
assert(typeof value == 'number');
// Possible |signalStrength| values should be 0, 25, 50, 75, and 100. Add
// <= checks for robustness.
- if (value <= 24)
+ if (value <= 24) {
return this.i18n('OncTether-SignalStrength_Weak');
- if (value <= 49)
+ }
+ if (value <= 49) {
return this.i18n('OncTether-SignalStrength_Okay');
- if (value <= 74)
+ }
+ if (value <= 74) {
return this.i18n('OncTether-SignalStrength_Good');
- if (value <= 99)
+ }
+ if (value <= 99) {
return this.i18n('OncTether-SignalStrength_Strong');
+ }
return this.i18n('OncTether-SignalStrength_VeryStrong');
}
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html
index 4a01756d94f..e225181824e 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html
@@ -10,7 +10,6 @@
<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/iron-input/iron-input.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="network_proxy_exclusions.html">
<link rel="import" href="network_proxy_input.html">
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 f5ca74c1d59..e30b6f2f465 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
@@ -139,15 +139,17 @@ Polymer({
/** @private */
networkPropertiesChanged_: function() {
- if (this.proxyIsUserModified_)
- return; // Ignore update.
+ if (this.proxyIsUserModified_) {
+ return;
+ } // Ignore update.
this.updateProxy_();
},
/** @private */
updateProxy_: function() {
- if (!this.networkProperties)
+ if (!this.networkProperties) {
return;
+ }
/** @type {!CrOnc.ProxySettings} */
const proxy = this.createDefaultProxySettings_();
@@ -268,20 +270,25 @@ Polymer({
Object.assign({}, defaultProxy));
} else {
// Remove properties with empty hosts to unset them.
- if (manual.HTTPProxy && !manual.HTTPProxy.Host)
+ if (manual.HTTPProxy && !manual.HTTPProxy.Host) {
delete manual.HTTPProxy;
- if (manual.SecureHTTPProxy && !manual.SecureHTTPProxy.Host)
+ }
+ if (manual.SecureHTTPProxy && !manual.SecureHTTPProxy.Host) {
delete manual.SecureHTTPProxy;
- if (manual.FTPProxy && !manual.FTPProxy.Host)
+ }
+ if (manual.FTPProxy && !manual.FTPProxy.Host) {
delete manual.FTPProxy;
- if (manual.SOCKS && !manual.SOCKS.Host)
+ }
+ if (manual.SOCKS && !manual.SOCKS.Host) {
delete manual.SOCKS;
+ }
}
this.savedManual_ = Object.assign({}, manual);
this.savedExcludeDomains_ = proxy.ExcludeDomains;
} else if (proxy.Type == CrOnc.ProxySettingsType.PAC) {
- if (!proxy.PAC)
+ if (!proxy.PAC) {
return;
+ }
}
this.fire('proxy-change', {field: 'ProxySettings', value: proxy});
this.proxyIsUserModified_ = false;
@@ -322,10 +329,11 @@ Polymer({
// If the new proxy type is fully configured, send it, otherwise set
// |proxyIsUserModified_| to true so that property updates do not
// overwrite user changes.
- if (proxyTypeChangeIsReady)
+ if (proxyTypeChangeIsReady) {
this.sendProxyChange_();
- else
+ } else {
this.proxyIsUserModified_ = true;
+ }
if (elementToFocus) {
this.async(() => {
@@ -347,8 +355,9 @@ Polymer({
/** @private */
onAddProxyExclusionTap_: function() {
const value = this.$.proxyExclusion.value;
- if (!value)
+ if (!value) {
return;
+ }
this.push('proxy_.ExcludeDomains', value);
// Clear input.
this.$.proxyExclusion.value = '';
@@ -360,8 +369,9 @@ Polymer({
* @private
*/
onAddProxyExclusionKeypress_: function(event) {
- if (event.key != 'Enter')
+ if (event.key != 'Enter') {
return;
+ }
event.stopPropagation();
this.onAddProxyExclusionTap_();
},
@@ -386,12 +396,15 @@ Polymer({
* @private
*/
getProxyTypeDesc_: function(proxyType) {
- if (proxyType == CrOnc.ProxySettingsType.MANUAL)
+ if (proxyType == CrOnc.ProxySettingsType.MANUAL) {
return this.i18n('networkProxyTypeManual');
- if (proxyType == CrOnc.ProxySettingsType.PAC)
+ }
+ if (proxyType == CrOnc.ProxySettingsType.PAC) {
return this.i18n('networkProxyTypePac');
- if (proxyType == CrOnc.ProxySettingsType.WPAD)
+ }
+ if (proxyType == CrOnc.ProxySettingsType.WPAD) {
return this.i18n('networkProxyTypeWpad');
+ }
return this.i18n('networkProxyTypeDirect');
},
@@ -410,14 +423,17 @@ Polymer({
* @private
*/
isEditable_: function(propertyName) {
- if (!this.editable || (this.isShared_() && !this.useSharedProxies))
+ if (!this.editable || (this.isShared_() && !this.useSharedProxies)) {
return false;
- if (!this.networkProperties.hasOwnProperty('ProxySettings'))
- return true; // No proxy settings defined, so not enforced.
+ }
+ if (!this.networkProperties.hasOwnProperty('ProxySettings')) {
+ return true;
+ } // No proxy settings defined, so not enforced.
const property = /** @type {!CrOnc.ManagedProperty|undefined} */ (
this.get('ProxySettings.' + propertyName, this.networkProperties));
- if (!property)
+ if (!property) {
return true;
+ }
return this.isPropertyEditable_(property);
},
@@ -445,12 +461,14 @@ Polymer({
* @private
*/
isSaveManualProxyEnabled_: function() {
- if (!this.proxyIsUserModified_)
+ if (!this.proxyIsUserModified_) {
return false;
+ }
const manual = this.proxy_.Manual;
const httpHost = this.get('HTTPProxy.Host', manual);
- if (this.useSameProxy_)
+ if (this.useSameProxy_) {
return !!httpHost;
+ }
return !!httpHost || !!this.get('SecureHTTPProxy.Host', manual) ||
!!this.get('FTPProxy.Host', manual) || !!this.get('SOCKS.Host', manual);
},
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 6dc6323608e..68179558267 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
@@ -53,8 +53,9 @@ Polymer({
*/
onValueChange_: function() {
let port = parseInt(this.value.Port, 10);
- if (isNaN(port))
+ if (isNaN(port)) {
port = 80;
+ }
this.value.Port = port;
this.fire('proxy-change', {value: this.value});
}
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 4bc791255de..4fc3e105e8b 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
@@ -96,19 +96,19 @@ Polymer({
*/
pin_: {
type: String,
- observer: 'pinOrProgressChange_',
+ observer: 'pinOrPukChange_',
},
pin_new1_: {
type: String,
- observer: 'pinOrProgressChange_',
+ observer: 'pinOrPukChange_',
},
pin_new2_: {
type: String,
- observer: 'pinOrProgressChange_',
+ observer: 'pinOrPukChange_',
},
puk_: {
type: String,
- observer: 'pinOrProgressChange_',
+ observer: 'pinOrPukChange_',
},
},
@@ -137,30 +137,35 @@ Polymer({
this.onEnterPinDialogCancel_();
this.$.enterPinDialog.close();
}
- if (this.$.changePinDialog.open)
+ if (this.$.changePinDialog.open) {
this.$.changePinDialog.close();
- if (this.$.unlockPinDialog.open)
+ }
+ if (this.$.unlockPinDialog.open) {
this.$.unlockPinDialog.close();
- if (this.$.unlockPukDialog.open)
+ }
+ if (this.$.unlockPukDialog.open) {
this.$.unlockPukDialog.close();
+ }
},
/** @private */
focusDialogInput_: function() {
- if (this.$.enterPinDialog.open)
+ if (this.$.enterPinDialog.open) {
this.$.enterPin.focus();
- else if (this.$.changePinDialog.open)
+ } else if (this.$.changePinDialog.open) {
this.$.changePinOld.focus()();
- else if (this.$.unlockPinDialog.open)
+ } else if (this.$.unlockPinDialog.open) {
this.$.unlockPin.focus();
- else if (this.$.unlockPukDialog.open)
+ } else if (this.$.unlockPukDialog.open) {
this.$.unlockPuk.focus();
+ }
},
/** @private */
networkPropertiesChanged_: function() {
- if (!this.networkProperties || !this.networkProperties.Cellular)
+ if (!this.networkProperties || !this.networkProperties.Cellular) {
return;
+ }
const simLockStatus = this.networkProperties.Cellular.SIMLockStatus;
this.pukRequired_ =
!!simLockStatus && simLockStatus.LockType == CrOnc.LockType.PUK;
@@ -206,6 +211,15 @@ Polymer({
!!this.pin_new1_ && !!this.pin_new2_;
},
+ /**
+ * Clears error message on user interacion.
+ * @private
+ */
+ pinOrPukChange_: function() {
+ this.error_ = ErrorType.NONE;
+ this.pinOrProgressChange_();
+ },
+
/** @private */
pukRequiredChanged_: function() {
if (this.$.unlockPukDialog.open) {
@@ -218,8 +232,9 @@ Polymer({
return;
}
- if (!this.pukRequired_)
+ if (!this.pukRequired_) {
return;
+ }
// If the PUK was activated while attempting to enter or change a pin,
// close the dialog and open the unlock PUK dialog.
@@ -236,8 +251,9 @@ Polymer({
this.$.unlockPinDialog.close();
showUnlockPuk = true;
}
- if (!showUnlockPuk)
+ if (!showUnlockPuk) {
return;
+ }
this.showUnlockPukDialog_();
},
@@ -248,8 +264,9 @@ Polymer({
* @private
*/
onSimLockEnabledChange_: function(event) {
- if (!this.networkProperties || !this.networkProperties.Cellular)
+ if (!this.networkProperties || !this.networkProperties.Cellular) {
return;
+ }
this.sendSimLockEnabled_ = event.target.checked;
this.error_ = ErrorType.NONE;
this.$.enterPin.value = '';
@@ -301,7 +318,7 @@ Polymer({
this.focusDialogInput_();
} else {
this.error_ = ErrorType.NONE;
- this.$.closeDialogs_();
+ this.closeDialogs_();
this.delayUpdateLockEnabled_();
}
});
@@ -314,11 +331,13 @@ Polymer({
*/
sendEnterPin_: function(event) {
event.stopPropagation();
- if (!this.enterPinEnabled_)
+ if (!this.enterPinEnabled_) {
return;
+ }
const pin = this.$.enterPin.value;
- if (!this.validatePin_(pin))
+ if (!this.validatePin_(pin)) {
return;
+ }
const simState = /** @type {!CrOnc.CellularSimState} */ ({
currentPin: pin,
requirePin: this.sendSimLockEnabled_,
@@ -333,8 +352,9 @@ Polymer({
*/
onChangePinTap_: function(event) {
event.stopPropagation();
- if (!this.networkProperties || !this.networkProperties.Cellular)
+ if (!this.networkProperties || !this.networkProperties.Cellular) {
return;
+ }
this.error_ = ErrorType.NONE;
this.$.changePinOld.value = '';
this.$.changePinNew1.value = '';
@@ -353,8 +373,9 @@ Polymer({
sendChangePin_: function(event) {
event.stopPropagation();
const newPin = this.$.changePinNew1.value;
- if (!this.validatePin_(newPin, this.$.changePinNew2.value))
+ if (!this.validatePin_(newPin, this.$.changePinNew2.value)) {
return;
+ }
const simState = /** @type {!CrOnc.CellularSimState} */ ({
requirePin: true,
currentPin: this.$.changePinOld.value,
@@ -385,8 +406,9 @@ Polymer({
sendUnlockPin_: function(event) {
event.stopPropagation();
const pin = this.$.unlockPin.value;
- if (!this.validatePin_(pin))
+ if (!this.validatePin_(pin)) {
return;
+ }
this.unlockCellularSim_(pin, '');
},
@@ -420,11 +442,13 @@ Polymer({
sendUnlockPuk_: function(event) {
event.stopPropagation();
const puk = this.$.unlockPuk.value;
- if (!this.validatePuk_(puk))
+ if (!this.validatePuk_(puk)) {
return;
+ }
const pin = this.$.unlockPin1.value;
- if (!this.validatePin_(pin, this.$.unlockPin2.value))
+ if (!this.validatePin_(pin, this.$.unlockPin2.value)) {
return;
+ }
this.unlockCellularSim_(pin, puk);
},
@@ -454,22 +478,24 @@ Polymer({
/** @private */
getErrorMsg_: function() {
- if (this.error_ == ErrorType.NONE)
+ if (this.error_ == ErrorType.NONE) {
return '';
+ }
// TODO(stevenjb): Translate
let msg;
- if (this.error_ == ErrorType.INCORRECT_PIN)
+ if (this.error_ == ErrorType.INCORRECT_PIN) {
msg = 'Incorrect PIN.';
- else if (this.error_ == ErrorType.INCORRECT_PUK)
+ } else if (this.error_ == ErrorType.INCORRECT_PUK) {
msg = 'Incorrect PUK.';
- else if (this.error_ == ErrorType.MISMATCHED_PIN)
+ } else if (this.error_ == ErrorType.MISMATCHED_PIN) {
msg = 'PIN values do not match.';
- else if (this.error_ == ErrorType.INVALID_PIN)
+ } else if (this.error_ == ErrorType.INVALID_PIN) {
msg = 'Invalid PIN.';
- else if (this.error_ == ErrorType.INVALID_PUK)
+ } else if (this.error_ == ErrorType.INVALID_PUK) {
msg = 'Invalid PUK.';
- else
+ } else {
return 'UNKNOWN ERROR';
+ }
const retriesLeft = this.simUnlockSent_ &&
this.get('Cellular.SIMLockStatus.RetriesLeft', this.networkProperties);
if (retriesLeft) {
@@ -488,8 +514,9 @@ Polymer({
* @private
*/
validatePin_: function(pin1, opt_pin2) {
- if (!pin1.length)
+ if (!pin1.length) {
return false;
+ }
if (pin1.length < PIN_MIN_LENGTH) {
this.error_ = ErrorType.INVALID_PIN;
return false;
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 f4e00640a40..1424d4320dd 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
@@ -197,7 +197,7 @@
}
</style>
- <div id="root" on-contextmenu="onContextMenu_" on-tap="focusInput_">
+ <div id="root" on-contextmenu="onContextMenu_" on-tap="onRootTap_">
<div id="pinInputDiv">
<cr-input id="pinInput" type="password" value="{{value}}"
is-input-rtl$="[[isInputRtl_(value)]]"
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 b208704a59f..5e5647bab88 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
@@ -185,7 +185,7 @@ Polymer({
* @param {number=} opt_selectionStart
* @param {number=} opt_selectionEnd
*/
- focus: function(opt_selectionStart, opt_selectionEnd) {
+ focusInput: function(opt_selectionStart, opt_selectionEnd) {
setTimeout(function() {
this.passwordElement_().focus();
this.selectionStart_ = opt_selectionStart || 0;
@@ -197,11 +197,11 @@ Polymer({
* Transfers focus to the input. Called when a non button element on the
* PIN button area is clicked to prevent focus from leaving the input.
*/
- focusInput_: function() {
+ onRootTap_: function() {
// Focus the input and place the selected region to its exact previous
// location, as this function will not be called by something that will also
// modify the input value.
- this.focus(this.selectionStart_, this.selectionEnd_);
+ this.focusInput(this.selectionStart_, this.selectionEnd_);
},
/** @private */
@@ -232,8 +232,9 @@ Polymer({
// button, therefore we transfer focus back to the input, but if a number
// button is tabbed into, it should keep focus, so users can use tab and
// spacebar/return to enter their PIN.
- if (!event.target.receivedFocusFromKeyboard)
- this.focus(selectionStart + 1, selectionStart + 1);
+ if (!event.target.receivedFocusFromKeyboard) {
+ this.focusInput(selectionStart + 1, selectionStart + 1);
+ }
event.stopImmediatePropagation();
},
@@ -249,8 +250,9 @@ Polymer({
* @param {string} previous
*/
onPinValueChange_: function(value, previous) {
- if (this.passwordElement)
+ if (this.passwordElement) {
this.passwordElement.value = value;
+ }
this.fire('pin-change', {pin: value});
},
@@ -264,9 +266,10 @@ Polymer({
// selected region of the input element. If it is just a caret, remove the
// character in front of the caret.
let selectionStart = this.selectionStart_;
- let selectionEnd = this.selectionEnd_;
- if (selectionStart == selectionEnd && selectionStart)
+ const selectionEnd = this.selectionEnd_;
+ if (selectionStart == selectionEnd && selectionStart) {
selectionStart--;
+ }
this.value = this.value.substring(0, selectionStart) +
this.value.substring(selectionEnd);
@@ -286,8 +289,9 @@ Polymer({
* @private
*/
onBackspaceTap_: function(event) {
- if (!event.target.receivedFocusFromKeyboard)
+ if (!event.target.receivedFocusFromKeyboard) {
return;
+ }
this.onPinClear_();
this.clearAndReset_();
@@ -307,8 +311,9 @@ Polymer({
setInterval(this.onPinClear_.bind(this), REPEAT_BACKSPACE_DELAY_MS);
}.bind(this), INITIAL_BACKSPACE_DELAY_MS);
- if (!event.target.receivedFocusFromKeyboard)
- this.focus(this.selectionStart_, this.selectionEnd_);
+ if (!event.target.receivedFocusFromKeyboard) {
+ this.focusInput(this.selectionStart_, this.selectionEnd_);
+ }
event.stopImmediatePropagation();
},
@@ -332,17 +337,19 @@ Polymer({
*/
onBackspacePointerUp_: function(event) {
// If an interval has started, do not fire event on pointer up.
- if (!this.repeatBackspaceIntervalId_)
+ if (!this.repeatBackspaceIntervalId_) {
this.onPinClear_();
+ }
this.clearAndReset_();
// Since on-down gives the input element focus, the input element will
// already have focus when on-up is called. This will actually bring up the
- // virtual keyboard, even if focus() is wrapped in a setTimeout. Blur the
- // input element first to workaround this.
+ // virtual keyboard, even if focusInput() is wrapped in a setTimeout. Blur
+ // the input element first to workaround this.
this.blur();
- if (!event.target.receivedFocusFromKeyboard)
- this.focus(this.selectionStart_, this.selectionEnd_);
+ if (!event.target.receivedFocusFromKeyboard) {
+ this.focusInput(this.selectionStart_, this.selectionEnd_);
+ }
event.stopImmediatePropagation();
},
@@ -354,18 +361,21 @@ Polymer({
*/
isValidEventForInput_: function(event) {
// Valid if the key is a number, and shift is not pressed.
- if ((event.keyCode >= 48 && event.keyCode <= 57) && !event.shiftKey)
+ if ((event.keyCode >= 48 && event.keyCode <= 57) && !event.shiftKey) {
return true;
+ }
// Valid if the key is one of the selected special keys defined in
// |PIN_INPUT_ALLOWED_NON_NUMBER_KEY_CODES|.
- if (PIN_INPUT_ALLOWED_NON_NUMBER_KEY_CODES.indexOf(event.keyCode) > -1)
+ if (PIN_INPUT_ALLOWED_NON_NUMBER_KEY_CODES.indexOf(event.keyCode) > -1) {
return true;
+ }
// Valid if the key is CTRL+A to allow users to quickly select the entire
// PIN.
- if (event.keyCode == 65 && event.ctrlKey)
+ if (event.keyCode == 65 && event.ctrlKey) {
return true;
+ }
// The rest of the keys are invalid.
return false;
@@ -417,8 +427,9 @@ Polymer({
* @private
*/
getInputPlaceholder_: function(enablePassword, enablePlaceholder) {
- if (!enablePlaceholder)
+ if (!enablePlaceholder) {
return '';
+ }
return enablePassword ? this.i18n('pinKeyboardPlaceholderPinPassword') :
this.i18n('pinKeyboardPlaceholderPin');
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 12eaf15b7b2..0b7999f6423 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
@@ -147,7 +147,7 @@ Polymer({
},
focus: function() {
- this.$.pinKeyboard.focus();
+ this.$.pinKeyboard.focusInput();
},
/** @override */
@@ -283,10 +283,11 @@ Polymer({
},
/**
- * @param {!CustomEvent} e Custom event containing the new pin.
- * @private */
+ * @param {!CustomEvent<{pin: string}>} e Custom event containing the new pin.
+ * @private
+ */
onPinChange_: function(e) {
- const newPin = /** @type {{pin: string}} */ (e.detail).pin;
+ const newPin = e.detail.pin;
if (!this.isConfirmStep) {
if (newPin) {
this.quickUnlockPrivate.checkCredential(
@@ -327,14 +328,15 @@ Polymer({
/** This is called by container object when user initiated submit. */
doSubmit: function() {
if (!this.isConfirmStep) {
- if (!this.enableSubmit)
+ if (!this.enableSubmit) {
return;
+ }
this.initialPin_ = this.pinKeyboardValue_;
this.pinKeyboardValue_ = '';
this.isConfirmStep = true;
this.onPinChange_(new CustomEvent(
'pin-change', {detail: {pin: this.pinKeyboardValue_}}));
- this.$.pinKeyboard.focus();
+ this.$.pinKeyboard.focusInput();
this.writeUma(LockScreenProgress.ENTER_PIN);
return;
}
@@ -344,7 +346,7 @@ Polymer({
this.showProblem_(MessageType.MISMATCH, ProblemType.ERROR);
this.enableSubmit = false;
// Focus the PIN keyboard and highlight the entire PIN.
- this.$.pinKeyboard.focus(0, this.pinKeyboardValue_.length + 1);
+ this.$.pinKeyboard.focusInput(0, this.pinKeyboardValue_.length + 1);
return;
}
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
index 7342022f0a8..1fd8478bf61 100644
--- 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
@@ -4,11 +4,13 @@
<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/icons.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/iron-icon/iron-icon.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="smb_browser_proxy.html">
@@ -27,10 +29,6 @@
@apply --cr-form-field-label;
}
- cr-input {
- --cr-input-error-display: none;
- }
-
cr-searchable-drop-down {
display: block;
--cr-searchable-drop-down-width: 472px;
@@ -55,27 +53,44 @@
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;
}
+
+ #name,
+ #username {
+ --cr-input-error-display: none;
+ }
+
+ #general-error-container {
+ height: 32px;
+ }
+
+ #general-error-icon {
+ --iron-icon-fill-color: var(--google-red-600);
+ }
+
+ #general-error-message {
+ color: var(--google-red-600);
+ display: inline-block;
+ font-size: 10px;
+ }
</style>
<cr-dialog id="dialog">
<div slot="title">[[i18n('addSmbShare')]]</div>
<div slot="body" spellcheck="false">
+ <div id="general-error-container">
+ <div hidden="[[!shouldShowGeneralError_(currentMountError_)]]">
+ <iron-icon id="general-error-icon" icon="cr:warning"></iron-icon>
+ <div id="general-error-message">[[generalErrorText_]]</div>
+ </div>
+ </div>
<cr-searchable-drop-down id="address" label="[[i18n('smbShareUrl')]]"
value="{{mountUrl_}}" items="[[discoveredShares_]]"
placeholder="\\server\share" on-change="onURLChanged_"
+ error-message-allowed
update-value-on-input autofocus>
</cr-searchable-drop-down>
<cr-input id="name" label="[[i18n('smbShareName')]]"
@@ -98,32 +113,23 @@
<div id="credentials"
hidden="[[!shouldShowCredentialUI_(authenticationMethod_)]]">
<cr-input id="username" label="[[i18n('smbShareUsername')]]"
- value="{{username_}}">
+ value="{{username_}}"
+ invalid="[[shouldShowCredentialError_(currentMountError_)]]">
</cr-input>
<cr-input id="password" type="password"
- label="[[i18n('smbSharePassword')]]" value="{{password_}}">
+ label="[[i18n('smbSharePassword')]]" value="{{password_}}"
+ invalid="[[shouldShowCredentialError_(currentMountError_)]]">
</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>
+ <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>
</cr-dialog>
</template>
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
index a309717b357..7ffad1b94e6 100644
--- 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
@@ -6,6 +6,20 @@
* @fileoverview 'add-smb-share-dialog' is a component for adding an SMB Share.
*/
+cr.define('smb_shares', function() {
+ /** @enum{number} */
+ const MountErrorType = {
+ NO_ERROR: 0,
+ CREDENTIAL_ERROR: 1,
+ PATH_ERROR: 2,
+ GENERAL_ERROR: 3,
+ };
+
+ return {
+ MountErrorType: MountErrorType,
+ };
+});
+
Polymer({
is: 'add-smb-share-dialog',
@@ -17,6 +31,11 @@ Polymer({
value: '',
},
+ shouldOpenFileManagerAfterMount: {
+ type: Boolean,
+ value: false,
+ },
+
/** @private {string} */
mountUrl_: {
type: String,
@@ -67,13 +86,19 @@ Polymer({
},
/** @private */
- addShareResultText_: String,
+ generalErrorText_: String,
/** @private */
inProgress_: {
type: Boolean,
value: false,
- }
+ },
+
+ /** @private {!smb_shares.MountErrorType} */
+ currentMountError_: {
+ type: Number,
+ value: smb_shares.MountErrorType.NO_ERROR,
+ },
},
/** @private {?smb_shares.SmbBrowserProxy} */
@@ -100,11 +125,13 @@ Polymer({
/** @private */
onAddButtonTap_: function() {
+ this.resetErrorState_();
this.inProgress_ = true;
this.browserProxy_
.smbMount(
this.mountUrl_, this.mountName_.trim(), this.username_,
- this.password_, this.authenticationMethod_)
+ this.password_, this.authenticationMethod_,
+ this.shouldOpenFileManagerAfterMount)
.then(result => {
this.onAddShare_(result);
});
@@ -112,6 +139,7 @@ Polymer({
/** @private */
onURLChanged_: function() {
+ this.resetErrorState_();
const parts = this.mountUrl_.split('\\');
this.mountName_ = parts[parts.length - 1];
},
@@ -146,35 +174,102 @@ Polymer({
*/
onAddShare_: function(result) {
this.inProgress_ = false;
+
+ // Success case. Close dialog.
+ if (result == SmbMountResult.SUCCESS) {
+ this.$.dialog.close();
+ return;
+ }
+
switch (result) {
- case SmbMountResult.SUCCESS:
- this.$.dialog.close();
- break;
+ // Credential Error
case SmbMountResult.AUTHENTICATION_FAILED:
- this.addShareResultText_ =
- loadTimeData.getString('smbShareAddedAuthFailedMessage');
+ this.setCredentialError_(
+ loadTimeData.getString('smbShareAddedAuthFailedMessage'));
break;
+
+ // Path Errors
case SmbMountResult.NOT_FOUND:
- this.addShareResultText_ =
- loadTimeData.getString('smbShareAddedNotFoundMessage');
+ this.setPathError_(
+ loadTimeData.getString('smbShareAddedNotFoundMessage'));
+ break;
+ case SmbMountResult.INVALID_URL:
+ this.setPathError_(
+ loadTimeData.getString('smbShareAddedInvalidURLMessage'));
break;
+
+ // General Errors
case SmbMountResult.UNSUPPORTED_DEVICE:
- this.addShareResultText_ =
- loadTimeData.getString('smbShareAddedUnsupportedDeviceMessage');
+ this.setGeneralError_(
+ loadTimeData.getString('smbShareAddedUnsupportedDeviceMessage'));
break;
case SmbMountResult.MOUNT_EXISTS:
- this.addShareResultText_ =
- loadTimeData.getString('smbShareAddedMountExistsMessage');
- break;
- case SmbMountResult.INVALID_URL:
- this.addShareResultText_ =
- loadTimeData.getString('smbShareAddedInvalidURLMessage');
+ this.setGeneralError_(
+ loadTimeData.getString('smbShareAddedMountExistsMessage'));
break;
default:
- this.addShareResultText_ =
- loadTimeData.getString('smbShareAddedErrorMessage');
+ this.setGeneralError_(
+ loadTimeData.getString('smbShareAddedErrorMessage'));
}
- this.$.errorToast.show();
},
+ /** @private */
+ resetErrorState_: function() {
+ this.currentMountError_ = smb_shares.MountErrorType.NO_ERROR;
+ this.$.address.errorMessage = '';
+ this.$.password.errorMessage = '';
+ this.generalErrorText_ = '';
+ },
+
+ /**
+ * @param {string} errorMessage
+ * @private
+ */
+ setCredentialError_: function(errorMessage) {
+ this.$.password.errorMessage = errorMessage;
+ this.currentMountError_ = smb_shares.MountErrorType.CREDENTIAL_ERROR;
+ },
+
+ /**
+ * @param {string} errorMessage
+ * @private
+ */
+ setGeneralError_: function(errorMessage) {
+ this.generalErrorText_ = errorMessage;
+ this.currentMountError_ = smb_shares.MountErrorType.GENERAL_ERROR;
+ },
+
+ /**
+ * @param {string} errorMessage
+ * @private
+ */
+ setPathError_: function(errorMessage) {
+ this.$.address.errorMessage = errorMessage;
+ this.currentMountError_ = smb_shares.MountErrorType.PATH_ERROR;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowCredentialError_: function() {
+ return this.currentMountError_ ==
+ smb_shares.MountErrorType.CREDENTIAL_ERROR;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowGeneralError_: function() {
+ return this.currentMountError_ == smb_shares.MountErrorType.GENERAL_ERROR;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowPathError_: function() {
+ return this.currentMountError_ == smb_shares.MountErrorType.PATH_ERROR;
+ },
});
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
index 7d345fbe013..43870ed30f9 100644
--- 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
@@ -44,29 +44,48 @@ cr.define('smb_shares', function() {
* @param {string} username
* @param {string} password
* @param {string} authMethod
+ * @param {boolean} shouldOpenFileManagerAfterMount
* @return {!Promise<SmbMountResult>}
*/
- smbMount(smbUrl, smbName, username, password, authMethod) {}
+ smbMount(
+ smbUrl, smbName, username, password, authMethod,
+ shouldOpenFileManagerAfterMount) {}
/**
* Starts the file share discovery process.
*/
startDiscovery() {}
+
+ /**
+ * Updates the credentials for a mounted share.
+ * @param {number} mountId
+ * @param {string} username
+ * @param {string} password
+ */
+ updateCredentials(mountId, username, password) {}
}
/** @implements {smb_shares.SmbBrowserProxy} */
class SmbBrowserProxyImpl {
/** @override */
- smbMount(smbUrl, smbName, username, password, authMethod) {
+ smbMount(
+ smbUrl, smbName, username, password, authMethod,
+ shouldOpenFileManagerAfterMount) {
return cr.sendWithPromise(
'smbMount', smbUrl, smbName, username, password,
- authMethod == SmbAuthMethod.KERBEROS);
+ authMethod == SmbAuthMethod.KERBEROS,
+ shouldOpenFileManagerAfterMount);
}
/** @override */
startDiscovery() {
chrome.send('startDiscovery');
}
+
+ /** @override */
+ updateCredentials(mountId, username, password) {
+ chrome.send('updateCredentials', [mountId, username, password]);
+ }
}
cr.addSingletonGetter(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 2c978f4adc1..8c5d906e1e7 100644
--- a/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp
+++ b/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp
@@ -324,14 +324,6 @@
file="cr_components/chromeos/multidevice_setup/password_page.js"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_SETUP_FAILED_PAGE_HTML"
- file="cr_components/chromeos/multidevice_setup/setup_failed_page.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_SETUP_FAILED_PAGE_JS"
- file="cr_components/chromeos/multidevice_setup/setup_failed_page.js"
- type="chrome_html"
- compress="gzip" />
<structure name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_SETUP_SUCCEEDED_PAGE_HTML"
file="cr_components/chromeos/multidevice_setup/setup_succeeded_page.html"
type="chrome_html"
@@ -383,4 +375,12 @@
type="chrome_html"
compress="gzip" />
</if>
+ <structure name="IDR_WEBUI_MANAGED_FOOTNOTE_HTML"
+ file="cr_components/managed_footnote/managed_footnote.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_WEBUI_MANAGED_FOOTNOTE_JS"
+ file="cr_components/managed_footnote/managed_footnote.js"
+ type="chrome_html"
+ compress="gzip" />
</grit-part>
diff --git a/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn b/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
new file mode 100644
index 00000000000..a5b2c6208e4
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
@@ -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("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":managed_footnote",
+ ]
+}
+
+js_library("managed_footnote") {
+ deps = [
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ "//ui/webui/resources/js:load_time_data",
+ ]
+}
diff --git a/chromium/ui/webui/resources/cr_components/managed_footnote/managed_footnote.html b/chromium/ui/webui/resources/cr_components/managed_footnote/managed_footnote.html
new file mode 100644
index 00000000000..04b3e91aee8
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/managed_footnote/managed_footnote.html
@@ -0,0 +1,48 @@
+<link rel="import" href="../../html/polymer.html">
+
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="../../cr_elements/icons.html">
+<link rel="import" href="../../cr_elements/shared_vars_css.html">
+<link rel="import" href="../../html/i18n_behavior.html">
+<link rel="import" href="../../html/load_time_data.html">
+
+<dom-module id="managed-footnote">
+ <template>
+ <style>
+ :host {
+ align-items: center;
+ border-top: 1px solid var(--cr-separator-color);
+ color: var(--cr-secondary-text-color);
+ display: none;
+ /* Should be 13px when <html> font-size is 16px */
+ font-size: 0.8125rem;
+ justify-content: center;
+ padding: 0 24px;
+ }
+
+ :host([is-managed_]) {
+ display: flex;
+ }
+
+ a[href] {
+ color: var(--cr-link-color);
+ text-decoration: none;
+ }
+
+ iron-icon {
+ align-self: flex-start;
+ flex-shrink: 0;
+ height: 20px;
+ padding-inline-end: var(--managed-footnote-icon-padding, 8px);
+ width: 20px;
+ }
+ </style>
+
+ <template is="dom-if" if="[[isManaged_]]">
+ <iron-icon icon="cr:domain"></iron-icon>
+ <div id="content" inner-h-t-m-l="[[message_]]"></div>
+ </template>
+ </template>
+ <script src="managed_footnote.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/managed_footnote/managed_footnote.js b/chromium/ui/webui/resources/cr_components/managed_footnote/managed_footnote.js
new file mode 100644
index 00000000000..09ce1cf2728
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/managed_footnote/managed_footnote.js
@@ -0,0 +1,69 @@
+// 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 indicating that this user is managed by
+ * their organization. This component uses the |isManaged| boolean in
+ * loadTimeData, and the |managedByOrg| i18n string.
+ *
+ * If |isManaged| is false, this component is hidden. If |isManaged| is true, it
+ * becomes visible.
+ */
+
+(function() {
+/**
+ * URL of the help article for the clickable link.
+ * @type {string}
+ */
+// TODO(nicolaso): Use a p-link instead, once it's available. b/117655761
+const HELP_ARTICLE_URL = 'https://support.google.com/chromebook/answer/1331549';
+
+Polymer({
+ is: 'managed-footnote',
+
+ behaviors: [I18nBehavior],
+
+ properties: {
+ /**
+ * Whether the browser is managed by their organization through enterprise
+ * policies.
+ * @private
+ */
+ isManaged_: {
+ reflectToAttribute: true,
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('isManaged');
+ },
+ },
+
+ /**
+ * Localized message to display in the footnote. May contain an <a>
+ * element.
+ * @private
+ */
+ message_: String,
+ },
+
+ /** @override */
+ ready: function() {
+ this.message_ = this.i18nAdvanced('managedByOrg', {
+ substitutions: [HELP_ARTICLE_URL],
+ tags: ['a'],
+ attrs: {
+ target: (node, v) => v === '_blank',
+ href: (node, v) => v === HELP_ARTICLE_URL,
+ },
+ });
+
+ cr.addWebUIListener('is-managed-changed', managed => {
+ loadTimeData.overrideValues({isManaged: managed});
+ this.isManaged_ = managed;
+ });
+ },
+});
+
+chrome.send('observeManagedUI');
+
+})();
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 50e7eabd04b..4720ce37c57 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
@@ -92,8 +92,9 @@ Polymer({
/** Only focuses the button if it's not disabled. */
focusTakePhotoButton: function() {
- if (this.cameraOnline_)
+ if (this.cameraOnline_) {
this.$.takePhoto.focus();
+ }
},
/**
@@ -102,8 +103,9 @@ Polymer({
* 'photoDataURL' property containing the photo encoded as a data URL.
*/
takePhoto: function() {
- if (!this.cameraOnline_ || this.cameraCaptureInProgress_)
+ if (!this.cameraOnline_ || this.cameraCaptureInProgress_) {
return;
+ }
this.cameraCaptureInProgress_ = true;
/** Pre-allocate all frames needed for capture. */
@@ -115,8 +117,9 @@ Polymer({
height: CAPTURE_SIZE.height / 2
};
const captureFrameCount = CAPTURE_DURATION_MS / CAPTURE_INTERVAL_MS;
- while (frames.length < captureFrameCount)
+ while (frames.length < captureFrameCount) {
frames.push(this.allocateFrame_(captureSize));
+ }
} else {
frames.push(this.allocateFrame_(CAPTURE_SIZE));
}
@@ -189,8 +192,9 @@ Polymer({
*/
stopVideoTracks_: function(stream) {
const tracks = stream.getVideoTracks();
- for (let i = 0; i < tracks.length; i++)
+ for (let i = 0; i < tracks.length; i++) {
tracks[i].stop();
+ }
},
/**
@@ -270,8 +274,9 @@ Polymer({
});
/** No need for further processing if single frame. */
- if (encodedImages.length == 1)
+ if (encodedImages.length == 1) {
return encodedImages[0];
+ }
/** Create forward/backward image sequence. */
const forwardBackwardImageSequence =
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 2187d436ead..5a666bc747f 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
@@ -119,8 +119,9 @@ Polymer({
setProfileImageUrl: function(imageUrl, selected) {
this.profileImageUrl_ = imageUrl;
this.$.profileImage.title = this.profileImageLabel;
- if (!selected)
+ if (!selected) {
return;
+ }
this.setSelectedImage_(this.$.profileImage);
},
@@ -181,8 +182,9 @@ Polymer({
/** @private */
onDefaultImagesChanged_: function() {
- if (this.selectedImageUrl_)
+ if (this.selectedImageUrl_) {
this.setSelectedImageUrl(this.selectedImageUrl_);
+ }
},
/**
@@ -190,8 +192,9 @@ Polymer({
* @param {!{detail: !{key: string, keyboardEvent: Object}}} e
*/
onKeysPressed_: function(e) {
- if (!this.selectedItem)
+ if (!this.selectedItem) {
return;
+ }
const selector = /** @type {IronSelectorElement} */ (this.$.selector);
const prevSelected = this.selectedItem;
@@ -231,8 +234,9 @@ Polymer({
this.selectedItem = selected;
if (selected.dataset.type == CrPicture.SelectionTypes.CAMERA) {
- if (activate)
+ if (activate) {
this.fire('focus-action', selected);
+ }
} else if (
activate || selected.dataset.type != CrPicture.SelectionTypes.FILE) {
this.fire('image-activate', selected);
@@ -255,8 +259,9 @@ Polymer({
* @private
*/
onSelectedItemChanged_: function(event) {
- if (event.target.selectedItem)
+ if (event.target.selectedItem) {
event.target.selectedItem.scrollIntoViewIfNeeded(false);
+ }
},
/**
@@ -267,15 +272,17 @@ Polymer({
*/
getImgSrc_: function(url) {
// Use first frame of animated user images.
- if (url.startsWith('chrome://theme'))
+ if (url.startsWith('chrome://theme')) {
return url + '[0]';
+ }
/**
* Extract first frame from image by creating a single frame PNG using
* url as input if base64 encoded and potentially animated.
*/
- if (url.split(',')[0] == 'data:image/png;base64')
+ if (url.split(',')[0] == 'data:image/png;base64') {
return CrPngBehavior.convertImageSequenceToPng([url]);
+ }
return url;
},
@@ -289,8 +296,9 @@ Polymer({
* @private
*/
getImgSrc2x_: function(url) {
- if (!url.startsWith('chrome://theme'))
+ if (!url.startsWith('chrome://theme')) {
return '';
+ }
return url + '[0]@2x 2x';
},
});
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html
index 0563c0f0273..551405bbdec 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html
@@ -67,7 +67,7 @@
<img id="image" alt="[[previewAltText]]" src="[[getImgSrc_(imageUrl)]]"
data-show-discard$="[[showDiscard_(imageType)]]">
<div id="discard" hidden="[[!showDiscard_(imageType)]]">
- <paper-icon-button-light class="icon-delete-white">
+ <paper-icon-button-light class="icon-picture-delete">
<button id="discardImage"
title="[[discardImageLabel]]"
on-tap="onTapDiscardImage_">
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 37b3f654ac4..a3fede76f91 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
@@ -64,16 +64,18 @@ Polymer({
*/
takePhoto: function() {
const camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
- if (camera)
+ if (camera) {
camera.takePhoto();
+ }
},
/** Tells the pane to focus the main action button. */
focusActionButton: function() {
- if (this.showDiscard_())
+ if (this.showDiscard_()) {
this.$.discardImage.focus();
- else if (this.cameraActive_)
+ } else if (this.cameraActive_) {
this.$$('#camera').focusTakePhotoButton();
+ }
},
/**
@@ -88,12 +90,14 @@ Polymer({
/** @private */
cameraActiveChanged_: function() {
const camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
- if (!camera)
- return; // Camera will be started when attached.
- if (this.cameraActive_)
+ if (!camera) {
+ return;
+ } // Camera will be started when attached.
+ if (this.cameraActive_) {
camera.startCamera();
- else
+ } else {
camera.stopCamera();
+ }
},
/** @private */
@@ -102,8 +106,9 @@ Polymer({
* If current image URL is an object URL created below then revoke it to
* prevent this code from using more than one object URL per document.
*/
- if (this.imageUrl.startsWith('blob:'))
+ if (this.imageUrl.startsWith('blob:')) {
URL.revokeObjectURL(this.imageUrl);
+ }
/**
* Data URLs for PNG images can be large. Create an object URL to avoid
@@ -113,8 +118,9 @@ Polymer({
if (this.imageSrc.startsWith('data:image/png')) {
const byteString = atob(this.imageSrc.split(',')[1]);
const bytes = new Uint8Array(byteString.length);
- for (let i = 0; i < byteString.length; i++)
+ for (let i = 0; i < byteString.length; i++) {
bytes[i] = byteString.charCodeAt(i);
+ }
const blob = new Blob([bytes], {'type': 'image/png'});
// Use first frame as placeholder while rest of image loads.
image.style.backgroundImage = 'url(' +
@@ -155,8 +161,9 @@ Polymer({
*/
getImgSrc_: function(url) {
// Always use 2x user image for preview.
- if (url.startsWith('chrome://theme'))
+ if (url.startsWith('chrome://theme')) {
return url + '@2x';
+ }
return url;
},
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 d57600ebfb1..3401fd9dd48 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
@@ -181,8 +181,9 @@ const CrPngBehavior = {
png.chunks.push(acTL);
/** Append each image as a PNG frame. */
- for (let 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. */
this.writeUInt32_(IHDR, png.width, 8);
@@ -424,20 +425,27 @@ const CrPngBehavior = {
}
/** Check that header matches our expectations. */
- if (width != png.width)
+ if (width != png.width) {
console.error('Bad PNG width: ' + width);
- if (height != png.height)
+ }
+ if (height != png.height) {
console.error('Bad PNG height: ' + height);
- if (depth != PNG_BIT_DEPTH)
+ }
+ if (depth != PNG_BIT_DEPTH) {
console.error('Bad PNG bit depth: ' + depth);
- if (colour != png.colour)
+ }
+ if (colour != png.colour) {
console.error('Bad PNG colour type: ' + colour);
- if (compression != PNG_COMPRESSION_METHOD)
+ }
+ if (compression != PNG_COMPRESSION_METHOD) {
console.error('Bad PNG compression method: ' + compression);
- if (filter != PNG_FILTER_METHOD)
+ }
+ if (filter != PNG_FILTER_METHOD) {
console.error('Bad PNG filter method: ' + filter);
- if (interlace != PNG_INTERLACE_METHOD)
+ }
+ if (interlace != PNG_INTERLACE_METHOD) {
console.error('Bad PNG interlace method: ' + interlace);
+ }
break;
case 'IDAT':
/** Append as IDAT chunk if this is the first frame. */
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/fingerprint/cr_fingerprint_progress_arc.js b/chromium/ui/webui/resources/cr_elements/chromeos/fingerprint/cr_fingerprint_progress_arc.js
index 275d2d3f36c..bf7e1c87371 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/fingerprint/cr_fingerprint_progress_arc.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/fingerprint/cr_fingerprint_progress_arc.js
@@ -162,8 +162,9 @@ Polymer({
* @param {boolean} isComplete Indicate whether enrollment is complete.
*/
setProgress: function(prevPercentComplete, currPercentComplete, isComplete) {
- if (this.isComplete_)
+ if (this.isComplete_) {
return;
+ }
this.isComplete_ = isComplete;
const slice = 2 * Math.PI / 100;
@@ -211,10 +212,11 @@ Polymer({
this.updateTimerId_ = undefined;
}
- if (isComplete)
+ if (isComplete) {
this.animateScanComplete_();
- else
+ } else {
this.animateScanProgress_();
+ }
},
/**
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 723ed41d021..a6359a1c92a 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
@@ -41,17 +41,27 @@ Polymer({
},
/**
+ * Number of network icons for different cellular or wifi network signal
+ * strengths.
+ * @private @const
+ */
+ networkIconCount_: 5,
+
+ /**
* @return {string} The name of the svg icon image to show.
* @private
*/
getIconClass_: function() {
- if (!this.networkState)
+ if (!this.networkState) {
return '';
+ }
const type = this.networkState.Type;
- if (type == CrOnc.Type.ETHERNET)
+ if (type == CrOnc.Type.ETHERNET) {
return 'ethernet';
- if (type == CrOnc.Type.VPN)
+ }
+ if (type == CrOnc.Type.VPN) {
return 'vpn';
+ }
const prefix = (type == CrOnc.Type.CELLULAR || type == CrOnc.Type.TETHER) ?
'cellular-' :
@@ -66,8 +76,9 @@ Polymer({
}
const connectionState = this.networkState.ConnectionState;
- if (connectionState == CrOnc.ConnectionState.CONNECTING)
+ if (connectionState == CrOnc.ConnectionState.CONNECTING) {
return prefix + 'connecting';
+ }
if (!this.isListItem &&
(!connectionState ||
@@ -81,13 +92,22 @@ Polymer({
/**
* @param {number} strength The signal strength from [0 - 100].
- * @return {number} An index from 0-4 corresponding to |strength|.
+ * @return {number} An index from 0 to |this.networkIconCount_ - 1|
+ * corresponding to |strength|.
* @private
*/
strengthToIndex_: function(strength) {
- if (strength == 0)
+ if (strength <= 0) {
return 0;
- return Math.min(Math.trunc((strength - 1) / 25) + 1, 4);
+ }
+
+ if (strength >= 100) {
+ return this.networkIconCount_ - 1;
+ }
+
+ const zeroBasedIndex =
+ Math.trunc((strength - 1) * (this.networkIconCount_ - 1) / 100);
+ return zeroBasedIndex + 1;
},
/**
@@ -104,16 +124,19 @@ Polymer({
*/
getTechnology_: function() {
const networkState = this.networkState;
- if (!networkState)
+ if (!networkState) {
return '';
+ }
const type = networkState.Type;
- if (type == CrOnc.Type.WI_MAX)
+ if (type == CrOnc.Type.WI_MAX) {
return 'network:4g';
+ }
if (type == CrOnc.Type.CELLULAR && networkState.Cellular) {
const technology =
this.getTechnologyId_(networkState.Cellular.NetworkTechnology);
- if (technology != '')
+ if (technology != '') {
return 'network:' + technology;
+ }
}
return '';
},
@@ -154,10 +177,12 @@ Polymer({
*/
showSecure_: function() {
const networkState = this.networkState;
- if (!this.networkState)
+ if (!this.networkState) {
return false;
- if (networkState.Type != CrOnc.Type.WI_FI || !networkState.WiFi)
+ }
+ if (networkState.Type != CrOnc.Type.WI_FI || !networkState.WiFi) {
return false;
+ }
if (!this.isListItem &&
networkState.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED) {
return false;
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 8d68577901c..e474e811656 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
@@ -98,8 +98,9 @@ Polymer({
focusFirstItem_: function() {
// Select the first cr-network-list-item if there is one.
const item = this.$$('cr-network-list-item');
- if (!item)
+ if (!item) {
return;
+ }
item.focus();
this.focusRequested_ = false;
},
@@ -110,8 +111,9 @@ Polymer({
* @private
*/
selectedItemChanged_: function() {
- if (this.selectedItem)
+ if (this.selectedItem) {
this.onItemAction_(this.selectedItem);
+ }
},
/**
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 b3fff16a2d3..5b4f0b4f219 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
@@ -72,11 +72,13 @@ Polymer({
/** @private */
networkStateChanged_: function() {
- if (!this.networkState)
+ if (!this.networkState) {
return;
+ }
const connectionState = this.networkState.ConnectionState;
- if (connectionState == this.connectionState_)
+ if (connectionState == this.connectionState_) {
return;
+ }
this.connectionState_ = connectionState;
this.fire('network-connect-changed', this.networkState);
},
@@ -90,8 +92,9 @@ Polymer({
if (this.item.hasOwnProperty('customItemName')) {
const item = /** @type {!CrNetworkList.CustomItemState} */ (this.item);
let name = item.customItemName || '';
- if (CrOncStrings.hasOwnProperty(item.customItemName))
+ if (CrOncStrings.hasOwnProperty(item.customItemName)) {
name = CrOncStrings[item.customItemName];
+ }
return name;
}
const network = /** @type {!CrOnc.NetworkStateProperties} */ (this.item);
@@ -112,21 +115,26 @@ Polymer({
* @private
*/
getNetworkStateText_: function() {
- if (!this.networkState)
+ if (!this.networkState) {
return '';
+ }
const connectionState = this.networkState.ConnectionState;
if (this.networkState.Type == CrOnc.Type.CELLULAR) {
// For Cellular, an empty ConnectionState indicates that the device is
// still initializing.
- if (!connectionState)
+ if (!connectionState) {
return CrOncStrings.networkListItemInitializing;
- if (this.networkState.Cellular && this.networkState.Cellular.Scanning)
+ }
+ if (this.networkState.Cellular && this.networkState.Cellular.Scanning) {
return CrOncStrings.networkListItemScanning;
+ }
}
- if (connectionState == CrOnc.ConnectionState.CONNECTED)
+ if (connectionState == CrOnc.ConnectionState.CONNECTED) {
return CrOncStrings.networkListItemConnected;
- if (connectionState == CrOnc.ConnectionState.CONNECTING)
+ }
+ if (connectionState == CrOnc.ConnectionState.CONNECTING) {
return CrOncStrings.networkListItemConnecting;
+ }
return '';
},
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 c467b9aa093..dfc2c389f8b 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
@@ -92,8 +92,9 @@ const CrNetworkListenerBehavior = {
*/
maybeDispatchEvent_: function(selectors, event) {
const element = this.$$(selectors);
- if (!element)
+ 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 ee42242945c..d7ee6e1aa55 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
@@ -115,8 +115,9 @@ Polymer({
/** @override */
detached: function() {
- if (this.scanIntervalId_ !== null)
+ if (this.scanIntervalId_ !== null) {
window.clearInterval(this.scanIntervalId_);
+ }
chrome.networkingPrivate.onNetworkListChanged.removeListener(
this.networkListChangedListener_);
chrome.networkingPrivate.onDeviceStateListChanged.removeListener(
@@ -191,8 +192,9 @@ Polymer({
this.cellularDeviceState_ = deviceStates.find(function(device) {
return device.Type == CrOnc.Type.CELLULAR;
});
- if (this.cellularDeviceState_)
+ if (this.cellularDeviceState_) {
this.ensureCellularNetwork_(networkStates);
+ }
this.networkStateList_ = networkStates;
this.fire('network-list-changed', networkStates);
@@ -262,13 +264,15 @@ Polymer({
}
}
- if (state.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED)
+ if (state.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED) {
return;
+ }
chrome.networkingPrivate.startConnect(state.GUID, function() {
const lastError = chrome.runtime.lastError;
- if (lastError && lastError != 'connecting')
+ 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 f5664dda588..55ce7a8dffe 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
@@ -224,8 +224,9 @@ CrOnc.VPNType = {
* if it exists, otherwise undefined.
*/
CrOnc.getActiveValue = function(property) {
- if (property == undefined)
+ if (property == undefined) {
return undefined;
+ }
if (typeof property != 'object' || Array.isArray(property)) {
console.error(
@@ -234,21 +235,25 @@ CrOnc.getActiveValue = function(property) {
}
// Return the Active value if it exists.
- if ('Active' in property)
+ if ('Active' in property) {
return property['Active'];
+ }
// If no Active value is defined, return the effective value.
if ('Effective' in property) {
const effective = property.Effective;
- if (effective in property)
+ if (effective in property) {
return property[effective];
+ }
}
// If no Effective value, return the UserSetting or SharedSetting.
- if ('UserSetting' in property)
+ if ('UserSetting' in property) {
return property['UserSetting'];
- if ('SharedSetting' in property)
+ }
+ if ('SharedSetting' in property) {
return property['SharedSetting'];
+ }
// Effective, UserEditable or DeviceEditable properties may not have a value
// set.
@@ -269,10 +274,12 @@ CrOnc.getActiveValue = function(property) {
* @return {string}
*/
CrOnc.getStateOrActiveString = function(property) {
- if (property === undefined)
+ if (property === undefined) {
return '';
- if (typeof property == 'string')
+ }
+ if (typeof property == 'string') {
return property;
+ }
return /** @type {string} */ (CrOnc.getActiveValue(property));
};
@@ -288,8 +295,9 @@ CrOnc.isSimpleProperty = function(property) {
'DeviceEditable'
];
for (const prop of requiredProperties) {
- if (prop in property)
+ if (prop in property) {
return true;
+ }
}
return false;
};
@@ -302,8 +310,9 @@ CrOnc.isSimpleProperty = function(property) {
*/
CrOnc.getActiveProperties = function(properties) {
'use strict';
- if (!properties)
+ if (!properties) {
return undefined;
+ }
const result = {};
const keys = Object.keys(properties);
for (let i = 0; i < keys.length; ++i) {
@@ -311,10 +320,11 @@ CrOnc.getActiveProperties = function(properties) {
const property = properties[k];
let propertyValue;
if (typeof property === 'object') {
- if (CrOnc.isSimpleProperty(property))
+ if (CrOnc.isSimpleProperty(property)) {
propertyValue = CrOnc.getActiveValue(property);
- else
+ } else {
propertyValue = CrOnc.getActiveProperties(property);
+ }
} else {
propertyValue = property;
}
@@ -341,22 +351,26 @@ CrOnc.getIPConfigForType = function(properties, type) {
ipConfig = ipConfigs[i];
ipType = ipConfig.Type ? /** @type {CrOnc.IPType} */ (ipConfig.Type) :
undefined;
- if (ipType == type)
+ if (ipType == type) {
break;
+ }
}
}
- if (type != CrOnc.IPType.IPV4)
+ if (type != CrOnc.IPType.IPV4) {
return type == ipType ? ipConfig : undefined;
+ }
const staticIpConfig =
/** @type {!CrOnc.IPConfigProperties|undefined} */ (
CrOnc.getActiveProperties(properties.StaticIPConfig));
- if (!staticIpConfig)
+ if (!staticIpConfig) {
return ipConfig;
+ }
// If there is no entry in IPConfigs for |type|, return the static config.
- if (!ipConfig)
+ if (!ipConfig) {
return staticIpConfig;
+ }
// Otherwise, merge the appropriate static values into the result.
if (staticIpConfig.IPAddress &&
@@ -381,14 +395,18 @@ CrOnc.getIPConfigForType = function(properties, type) {
*/
CrOnc.getSignalStrength = function(properties) {
const type = properties.Type;
- if (type == CrOnc.Type.CELLULAR && properties.Cellular)
+ if (type == CrOnc.Type.CELLULAR && properties.Cellular) {
return properties.Cellular.SignalStrength || 0;
- if (type == CrOnc.Type.TETHER && properties.Tether)
+ }
+ if (type == CrOnc.Type.TETHER && properties.Tether) {
return properties.Tether.SignalStrength || 0;
- if (type == CrOnc.Type.WI_FI && properties.WiFi)
+ }
+ if (type == CrOnc.Type.WI_FI && properties.WiFi) {
return properties.WiFi.SignalStrength || 0;
- if (type == CrOnc.Type.WI_MAX && properties.WiMAX)
+ }
+ if (type == CrOnc.Type.WI_MAX && properties.WiMAX) {
return properties.WiMAX.SignalStrength || 0;
+ }
return 0;
};
@@ -402,14 +420,18 @@ CrOnc.getSignalStrength = function(properties) {
*/
CrOnc.getManagedAutoConnect = function(properties) {
const type = properties.Type;
- if (type == CrOnc.Type.CELLULAR && properties.Cellular)
+ if (type == CrOnc.Type.CELLULAR && properties.Cellular) {
return properties.Cellular.AutoConnect;
- if (type == CrOnc.Type.VPN && properties.VPN)
+ }
+ if (type == CrOnc.Type.VPN && properties.VPN) {
return properties.VPN.AutoConnect;
- if (type == CrOnc.Type.WI_FI && properties.WiFi)
+ }
+ if (type == CrOnc.Type.WI_FI && properties.WiFi) {
return properties.WiFi.AutoConnect;
- if (type == CrOnc.Type.WI_MAX && properties.WiMAX)
+ }
+ if (type == CrOnc.Type.WI_MAX && properties.WiMAX) {
return properties.WiMAX.AutoConnect;
+ }
return undefined;
};
@@ -430,12 +452,14 @@ CrOnc.getAutoConnect = function(properties) {
* @return {string} The name to display for |network|.
*/
CrOnc.getNetworkName = function(properties) {
- if (!properties)
+ if (!properties) {
return '';
+ }
const name = CrOnc.getStateOrActiveString(properties.Name);
const type = CrOnc.getStateOrActiveString(properties.Type);
- if (!name)
+ if (!name) {
return CrOncStrings['OncType' + type];
+ }
if (type == 'VPN' && properties.VPN) {
const vpnType = CrOnc.getStateOrActiveString(properties.VPN.Type);
if (vpnType == 'ThirdPartyVPN' && properties.VPN.ThirdPartyVPN) {
@@ -465,11 +489,13 @@ CrOnc.getEscapedNetworkName = function(properties) {
* locked SIM.
*/
CrOnc.isSimLocked = function(properties) {
- if (!properties.Cellular)
+ if (!properties.Cellular) {
return false;
+ }
const simLockStatus = properties.Cellular.SIMLockStatus;
- if (simLockStatus == undefined)
+ if (simLockStatus == undefined) {
return false;
+ }
return simLockStatus.LockType == CrOnc.LockType.PIN ||
simLockStatus.LockType == CrOnc.LockType.PUK;
};
@@ -495,8 +521,9 @@ CrOnc.setValidStaticIPConfig = function(config, properties) {
}
if (config.IPAddressConfigType != CrOnc.IPConfigType.STATIC &&
config.NameServersConfigType != CrOnc.IPConfigType.STATIC) {
- if (config.hasOwnProperty('StaticIPConfig'))
+ if (config.hasOwnProperty('StaticIPConfig')) {
delete config.StaticIPConfig;
+ }
return;
}
@@ -531,18 +558,21 @@ CrOnc.setValidStaticIPConfig = function(config, properties) {
CrOnc.setProperty = function(properties, key, value) {
while (true) {
const index = key.indexOf('.');
- if (index < 0)
+ if (index < 0) {
break;
+ }
const keyComponent = key.substr(0, index);
- if (!properties.hasOwnProperty(keyComponent))
+ if (!properties.hasOwnProperty(keyComponent)) {
properties[keyComponent] = {};
+ }
properties = properties[keyComponent];
key = key.substr(index + 1);
}
- if (value === undefined)
+ if (value === undefined) {
delete properties[key];
- else
+ } else {
properties[key] = value;
+ }
};
/**
@@ -571,8 +601,9 @@ CrOnc.setTypeProperty = function(properties, key, value) {
CrOnc.getRoutingPrefixAsNetmask = function(prefixLength) {
'use strict';
// Return the empty string for invalid inputs.
- if (prefixLength < 0 || prefixLength > 32)
+ if (prefixLength < 0 || prefixLength > 32) {
return '';
+ }
let netmask = '';
for (let i = 0; i < 4; ++i) {
let remainder = 8;
@@ -582,11 +613,13 @@ CrOnc.getRoutingPrefixAsNetmask = function(prefixLength) {
remainder = prefixLength;
prefixLength = 0;
}
- if (i > 0)
+ if (i > 0) {
netmask += '.';
+ }
let value = 0;
- if (remainder != 0)
+ if (remainder != 0) {
value = ((2 << (remainder - 1)) - 1) << (8 - remainder);
+ }
netmask += value.toString();
}
return netmask;
@@ -601,15 +634,17 @@ CrOnc.getRoutingPrefixAsLength = function(netmask) {
'use strict';
let prefixLength = 0;
const tokens = netmask.split('.');
- if (tokens.length != 4)
+ if (tokens.length != 4) {
return -1;
+ }
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) {
- if (token != '0')
+ if (token != '0') {
return -1;
+ }
} else if (token == '255') {
prefixLength += 8;
} else if (token == '254') {
@@ -652,8 +687,9 @@ CrOnc.proxyMatches = function(a, b) {
*/
CrOnc.shouldShowTetherDialogBeforeConnection = function(networkProperties) {
// Only show for Tether networks.
- if (networkProperties.Type != CrOnc.Type.TETHER)
+ if (networkProperties.Type != CrOnc.Type.TETHER) {
return false;
+ }
// Show if there are no Tether properties or if there are Tether properties
// and they indicate that a connection has not yet occurred to this host.
@@ -667,7 +703,8 @@ CrOnc.shouldShowTetherDialogBeforeConnection = function(networkProperties) {
* @return {!CrOnc.Type|undefined}
*/
CrOnc.getValidType = function(typeStr) {
- if (Object.values(CrOnc.Type).indexOf(typeStr) >= 0)
+ if (Object.values(CrOnc.Type).indexOf(typeStr) >= 0) {
return /** @type {!CrOnc.Type} */ (typeStr);
+ }
return undefined;
};
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 4b59b25bc40..8d66c290623 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
@@ -9,13 +9,14 @@
<template>
<style>
:host dialog {
- background-color: white;
+ background-color: var(--cr-menu-background-color);
border: none;
border-radius: 4px;
- box-shadow: 0 2px 6px var(--paper-grey-500);
+ box-shadow: var(--cr-menu-shadow);
margin: 0;
+ min-width: 128px;
outline: none;
- padding: 8px 0;
+ padding: 0;
@apply --cr-action-menu-dialog;
}
@@ -29,7 +30,7 @@
border: none;
border-radius: 0;
box-sizing: border-box;
- color: var(--paper-grey-900);
+ color: var(--cr-primary-text-color);
font: inherit;
min-height: 32px;
padding: 0 24px;
@@ -52,18 +53,20 @@
}
:host ::slotted(.dropdown-item:focus) {
- background-color: var(--google-grey-200);
+ background-color: var(--cr-menu-background-focus-color);
outline: none;
}
.item-wrapper {
+ background: var(--cr-menu-background-sheen);
outline: none;
+ padding: 8px 0;
}
</style>
<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>
+ <slot id="contentNode"></slot>
</div>
</dialog>
</template>
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 477e0ed7456..086b8bce480 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
@@ -50,6 +50,10 @@ const AnchorAlignment = {
const DROPDOWN_ITEM_CLASS = 'dropdown-item';
(function() {
+
+/** @const {number} */
+const AFTER_END_OFFSET = 10;
+
/**
* Returns the point to start along the X or Y axis given a start and end
* point to anchor to, the length of the target and the direction to anchor
@@ -85,10 +89,12 @@ function getStartPointWithAnchor(
break;
}
- if (startPoint + menuLength > max)
+ if (startPoint + menuLength > max) {
startPoint = end - menuLength;
- if (startPoint < min)
+ }
+ if (startPoint < min) {
startPoint = start;
+ }
startPoint = Math.max(min, Math.min(startPoint, max - menuLength));
@@ -201,8 +207,9 @@ Polymer({
*/
onNativeDialogClose_: function(e) {
// Ignore any 'close' events not fired directly by the <dialog> element.
- if (e.target !== this.$.dialog)
+ if (e.target !== this.$.dialog) {
return;
+ }
// TODO(dpapad): This is necessary to make the code work both for Polymer 1
// and Polymer 2. Remove once migration to Polymer 2 is completed.
@@ -237,10 +244,29 @@ Polymer({
return;
}
- if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp')
+ let selectNext = e.key == 'ArrowDown';
+ if (e.key == 'Enter') {
+ // If a menu item has focus, don't change focus or close menu on 'Enter'.
+ const options = this.querySelectorAll('.dropdown-item');
+ const focusedIndex =
+ Array.prototype.indexOf.call(options, getDeepActiveElement());
+ if (focusedIndex != -1) {
+ return;
+ }
+
+ if (cr.isWindows || cr.isMac) {
+ this.close();
+ e.preventDefault();
+ return;
+ }
+ selectNext = true;
+ }
+
+ if (e.key !== 'ArrowUp' && !selectNext) {
return;
+ }
- const nextOption = this.getNextOption_(e.key == 'ArrowDown' ? 1 : -1);
+ const nextOption = this.getNextOption_(selectNext ? 1 : -1);
if (nextOption) {
if (!this.hasMousemoveListener_) {
this.hasMousemoveListener_ = true;
@@ -295,14 +321,16 @@ Polymer({
Array.prototype.indexOf.call(options, getDeepActiveElement());
// Handle case where nothing is focused and up is pressed.
- if (focusedIndex === -1 && step === -1)
+ if (focusedIndex === -1 && step === -1) {
focusedIndex = 0;
+ }
do {
focusedIndex = (numOptions + focusedIndex + step) % numOptions;
nextOption = options[focusedIndex];
- if (nextOption.disabled || nextOption.hidden)
+ if (nextOption.disabled || nextOption.hidden) {
nextOption = null;
+ }
counter++;
} while (!nextOption && counter < numOptions);
@@ -335,11 +363,22 @@ Polymer({
this.anchorElement_.scrollIntoViewIfNeeded();
const rect = this.anchorElement_.getBoundingClientRect();
+
+ let height = rect.height;
+ if (opt_config &&
+ opt_config.anchorAlignmentY == AnchorAlignment.AFTER_END) {
+ // When an action menu is positioned after the end of an element, the
+ // action menu can appear too far away from the anchor element, typically
+ // because anchors tend to have padding. So we offset the height a bit
+ // so the menu shows up slightly closer to the content of anchor.
+ height -= AFTER_END_OFFSET;
+ }
+
this.showAtPosition(/** @type {ShowAtPositionConfig} */ (Object.assign(
{
top: rect.top,
left: rect.left,
- height: rect.height,
+ height: height,
width: rect.width,
// Default to anchoring towards the left.
anchorAlignmentX: AnchorAlignment.BEFORE_END,
@@ -429,8 +468,9 @@ Polymer({
// Flip the X anchor in RTL.
const rtl = getComputedStyle(this).direction == 'rtl';
- if (rtl)
+ if (rtl) {
c.anchorAlignmentX *= -1;
+ }
const offsetWidth = this.$.dialog.offsetWidth;
const menuLeft = getStartPointWithAnchor(
@@ -455,8 +495,9 @@ Polymer({
*/
addListeners_: function() {
this.boundClose_ = this.boundClose_ || function() {
- if (this.$.dialog.open)
+ if (this.$.dialog.open) {
this.close();
+ }
}.bind(this);
window.addEventListener('resize', this.boundClose_);
window.addEventListener('popstate', this.boundClose_);
diff --git a/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html b/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html
index 64e279b4f72..8981f1238d8 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html
@@ -29,11 +29,34 @@ List of customizable styles:
outline: none;
user-select: none;
- --cr-checkbox-size: 16px;
+ /* Sizes. */
--cr-checkbox-border-size: 2px;
+ --cr-checkbox-size: 16px;
--cr-checkbox-ripple-size: 40px;
+
+ /* Derived sizes (offsets). */
--cr-checkbox-ripple-offset: calc(var(--cr-checkbox-size)/2 -
var(--cr-checkbox-ripple-size)/2 - var(--cr-checkbox-border-size));
+
+ /* Light mode colors. */
+ --cr-checkbox-checked-box-color: var(--google-blue-600);
+ --cr-checkbox-checked-ripple-opacity: .2;
+ --cr-checkbox-mark-color: white;
+ --cr-checkbox-ripple-checked-color: var(--google-blue-600);
+ --cr-checkbox-ripple-unchecked-color: var(--google-grey-600);
+ --cr-checkbox-unchecked-box-color: var(--google-grey-refresh-700);
+ --cr-checkbox-unchecked-ripple-opacity: .15;
+ }
+
+ :host-context([dark]) {
+ /* Dark mode colors. */
+ --cr-checkbox-checked-box-color: var(--google-blue-300);
+ --cr-checkbox-checked-ripple-opacity: .4;
+ --cr-checkbox-mark-color: var(--google-grey-900);
+ --cr-checkbox-ripple-checked-color: var(--google-blue-300);
+ --cr-checkbox-ripple-unchecked-color: var(--google-grey-refresh-700);
+ --cr-checkbox-unchecked-box-color: var(--google-grey-refresh-500);
+ --cr-checkbox-unchecked-ripple-opacity: .4;
}
:host([disabled]) {
@@ -45,7 +68,7 @@ List of customizable styles:
#checkbox {
background: none;
border: var(--cr-checkbox-border-size) solid
- var(--cr-checkbox-unchecked-box-color, var(--google-grey-refresh-700));
+ var(--cr-checkbox-unchecked-box-color);
border-radius: 2px;
box-sizing: border-box;
cursor: pointer;
@@ -61,7 +84,7 @@ List of customizable styles:
}
#checkmark {
- border-color: var(--cr-checkbox-mark-color, white);
+ border-color: var(--cr-checkbox-mark-color);
border-style: solid;
border-width: 0 2px 2px 0;
content: '';
@@ -77,10 +100,8 @@ List of customizable styles:
}
:host([checked]) #checkbox {
- background: var(--cr-checkbox-checked-box-color,
- var(--google-blue-600));
- border-color: var(--cr-checkbox-checked-box-color,
- var(--google-blue-600));
+ background: var(--cr-checkbox-checked-box-color);
+ border-color: var(--cr-checkbox-checked-box-color);
}
:host([checked]) #checkmark {
@@ -90,8 +111,9 @@ List of customizable styles:
}
paper-ripple {
- --paper-ripple-opacity: var(--cr-checkbox-ripple-opacity, 0.15);
- color: var(--cr-checkbox-ripple-unchecked-color, var(--google-grey-600));
+ --paper-ripple-opacity: var(--cr-checkbox-ripple-opacity,
+ var(--cr-checkbox-unchecked-ripple-opacity));
+ color: var(--cr-checkbox-ripple-unchecked-color);
height: var(--cr-checkbox-ripple-size);
left: var(--cr-checkbox-ripple-offset);
pointer-events: none;
@@ -101,8 +123,9 @@ List of customizable styles:
}
:host([checked]) paper-ripple {
- --paper-ripple-opacity: var(--cr-checkbox-ripple-opacity, 0.2);
- color: var(--cr-checkbox-ripple-checked-color, var(--google-blue-600));
+ --paper-ripple-opacity: var(--cr-checkbox-ripple-opacity,
+ var(--cr-checkbox-checked-ripple-opacity));
+ color: var(--cr-checkbox-ripple-checked-color);
}
:host-context([dir=rtl]) paper-ripple {
@@ -111,7 +134,7 @@ List of customizable styles:
}
#label-container {
- color: var(--cr-checkbox-label-color, var(--google-grey-900));
+ color: var(--cr-checkbox-label-color, var(--cr-primary-text-color));
padding-inline-start: 20px;
white-space: normal;
@@ -125,7 +148,8 @@ List of customizable styles:
<!-- Mousing down then moving cursor out of this element should not trigger
click on the parent. With <button> this works as expected, while <div>
does not. -->
- <button id="checkbox" tabindex="-1" on-focus="onButtonFocus_">
+ <button id="checkbox" tabindex="-1" on-focus="onButtonFocus_"
+ aria-hidden="true">
<span id="checkmark"></span>
</button>
<div id="label-container"><slot></slot></div>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js b/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js
index 671eb38b9d7..7dd5b113bd0 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js
@@ -61,8 +61,9 @@ Polymer({
* @private
*/
disabledChanged_: function(current, previous) {
- if (previous === undefined && !this.disabled)
+ if (previous === undefined && !this.disabled) {
return;
+ }
this.setAttribute('tabindex', this.disabled ? -1 : 0);
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
@@ -94,8 +95,9 @@ Polymer({
* @private
*/
onClick_: function(e) {
- if (!this.shouldHandleEvent_(e))
+ if (!this.shouldHandleEvent_(e)) {
return;
+ }
// Prevent |click| event from bubbling. It can cause parents of this
// elements to erroneously re-toggle this control.
@@ -125,8 +127,9 @@ Polymer({
* @private
*/
onKeyPress_: function(e) {
- if (!this.shouldHandleEvent_(e) || (e.key != ' ' && e.key != 'Enter'))
+ if (!this.shouldHandleEvent_(e) || (e.key != ' ' && e.key != 'Enter')) {
return;
+ }
e.preventDefault();
this.toggleState_(true);
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 1c6789f9956..623aee060fb 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
@@ -52,8 +52,9 @@ const CrContainerShadowBehavior = {
// the drop shadow flashes once on startup, because of the DOM modifications
// earlier in this function causing a relayout.
window.setTimeout(() => {
- if (this.intersectionObserver_) // In case this is already detached.
+ if (this.intersectionObserver_) { // In case this is already detached.
this.intersectionObserver_.observe(intersectionProbe);
+ }
});
},
diff --git a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
index d9dcfac936b..b2f4fedb91c 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
@@ -10,7 +10,8 @@
<template>
<style include="cr-hidden-style cr-icons">
dialog {
- --scroll-border: 1px solid var(--paper-grey-300);
+ --scroll-border-color: var(--paper-grey-300);
+ --scroll-border: 1px solid var(--scroll-border-color);
border: 0;
border-radius: 8px;
bottom: 50%;
@@ -24,6 +25,15 @@
@apply --cr-dialog-native;
}
+ :host-context([dark]) dialog {
+ --scroll-border-color: var(--google-grey-refresh-700);
+ background-color: var(--google-grey-900);
+ /* Note: the colors in linear-gradient() are intentionally the same to
+ * add a 4% white layer on top of the fully opaque background-color. */
+ background-image: linear-gradient(rgba(255, 255, 255, .04),
+ rgba(255, 255, 255, .04));
+ }
+
dialog[open] #content-wrapper {
/* Keep max-height within viewport, and flex content accordingly. */
display: flex;
@@ -112,6 +122,10 @@
padding: 16px 20px;
}
+ :host-context([dark]) ::slotted([slot=footer]) {
+ border-top-color: var(--cr-separator-color);
+ }
+
.body-container {
/* Prevent layout moving when border does appear. */
border-bottom: 1px solid transparent;
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 9d71e19854f..55459ef89a1 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
@@ -99,12 +99,14 @@ Polymer({
// If the active history entry changes (i.e. user clicks back button),
// all open dialogs should be cancelled.
window.addEventListener('popstate', function() {
- if (!this.ignorePopstate && this.$.dialog.open)
+ if (!this.ignorePopstate && this.$.dialog.open) {
this.cancel();
+ }
}.bind(this));
- if (!this.ignoreEnterKey)
+ if (!this.ignoreEnterKey) {
this.addEventListener('keypress', this.onKeypress_.bind(this));
+ }
},
/** @override */
@@ -128,8 +130,9 @@ Polymer({
// In some cases dialog already has the 'open' attribute by this point.
mutationObserverCallback();
- if (this.showOnAttach)
+ if (this.showOnAttach) {
this.showModal();
+ }
},
/** @override */
@@ -144,8 +147,9 @@ Polymer({
/** @private */
addIntersectionObserver_: function() {
- if (this.intersectionObserver_)
+ if (this.intersectionObserver_) {
return;
+ }
const bodyContainer = this.$$('.body-container');
@@ -188,8 +192,9 @@ Polymer({
/** @private */
addKeydownListener_: function() {
- if (!this.consumeKeydownEvent)
+ if (!this.consumeKeydownEvent) {
return;
+ }
this.boundKeydown_ = this.boundKeydown_ || this.onKeydown_.bind(this);
@@ -203,8 +208,9 @@ Polymer({
/** @private */
removeKeydownListener_: function() {
- if (!this.boundKeydown_)
+ if (!this.boundKeydown_) {
return;
+ }
this.removeEventListener('keydown', this.boundKeydown_);
document.body.removeEventListener('keydown', this.boundKeydown_);
@@ -247,8 +253,9 @@ Polymer({
*/
onNativeDialogClose_: function(e) {
// Ignore any 'close' events not fired directly by the <dialog> element.
- if (e.target !== this.getNative())
+ if (e.target !== this.getNative()) {
return;
+ }
// TODO(dpapad): This is necessary to make the code work both for Polymer 1
// and Polymer 2. Remove once migration to Polymer 2 is completed.
@@ -265,8 +272,9 @@ Polymer({
*/
onNativeDialogCancel_: function(e) {
// Ignore any 'cancel' events not fired directly by the <dialog> element.
- if (e.target !== this.getNative())
+ if (e.target !== this.getNative()) {
return;
+ }
if (this.noCancel) {
e.preventDefault();
@@ -302,12 +310,14 @@ Polymer({
* @private
*/
onKeypress_: function(e) {
- if (e.key != 'Enter')
+ if (e.key != 'Enter') {
return;
+ }
// Accept Enter keys from either the dialog, or a child input element.
- if (e.target != this && e.target.tagName != 'CR-INPUT')
+ if (e.target != this && e.target.tagName != 'CR-INPUT') {
return;
+ }
const actionButton =
this.querySelector('.action-button:not([disabled]):not([hidden])');
@@ -324,11 +334,13 @@ Polymer({
onKeydown_: function(e) {
assert(this.consumeKeydownEvent);
- if (!this.getNative().open)
+ if (!this.getNative().open) {
return;
+ }
- if (this.ignoreEnterKey && e.key == 'Enter')
+ if (this.ignoreEnterKey && e.key == 'Enter') {
return;
+ }
// Stop propagation to behave modally.
e.stopPropagation();
@@ -338,8 +350,9 @@ Polymer({
onPointerdown_: function(e) {
// Only show pulse animation if user left-clicked outside of the dialog
// contents.
- if (e.button != 0 || e.composedPath()[0].tagName !== 'DIALOG')
+ if (e.button != 0 || e.composedPath()[0].tagName !== 'DIALOG') {
return;
+ }
this.$.dialog.animate(
[
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 eae9c1c22ff..f068f79aec6 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
@@ -23,6 +23,11 @@
width: var(--drawer-width);
}
+ :host-context([dark]) dialog {
+ background: var(--google-grey-900)
+ linear-gradient(rgba(255, 255, 255, .04), rgba(255, 255, 255, .04));
+ }
+
:host dialog,
#container {
height: 100%;
@@ -68,6 +73,10 @@
padding-inline-start: 24px;
}
+ :host-context([dark]) .drawer-header {
+ color: var(--cr-primary-text-color);
+ }
+
:host ::slotted(.drawer-content) {
height: calc(100% - 56px);
overflow: auto;
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 5ba1e551929..e3be0c995ea 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
@@ -33,16 +33,18 @@ Polymer({
/** Toggles the drawer open and close. */
toggle: function() {
- if (this.open)
+ if (this.open) {
this.cancel();
- else
+ } else {
this.openDrawer();
+ }
},
/** Shows drawer and slides it into view. */
openDrawer: function() {
- if (this.open)
+ if (this.open) {
return;
+ }
this.$.dialog.showModal();
this.show_ = true;
this.fire('cr-drawer-opening');
@@ -58,8 +60,9 @@ Polymer({
* @param {boolean} cancel
*/
dismiss_: function(cancel) {
- if (!this.open)
+ if (!this.open) {
return;
+ }
this.show_ = false;
listenOnce(this.$.dialog, 'transitionend', () => {
this.$.dialog.close(cancel ? 'canceled' : 'closed');
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 bee36844e23..066ce1255bf 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
@@ -2,11 +2,18 @@
<link rel="import" href="../cr_icons_css.html">
<link rel="import" href="../shared_style_css.html">
+<link rel="import" href="../shared_vars_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<dom-module id="cr-expand-button">
<template>
<style include="cr-icons cr-shared-style">
+ :host {
+ @apply --cr-actionable;
+ align-items: center;
+ display: flex;
+ }
+
:host([disabled]) {
opacity: 0.65;
pointer-events: none;
@@ -16,24 +23,19 @@
@apply --cr-paper-icon-button-margin;
}
- #outer {
- align-items: center;
- display: flex;
- }
-
#label {
flex: 1;
+ padding: var(--cr-section-vertical-padding) 0;
}
</style>
- <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)]]"
- tabindex$="[[tabIndex]]">
- </button>
- </paper-icon-button-light>
- </div>
+
+ <div id="label"><slot></slot></div>
+ <paper-icon-button-light class$="[[iconName_(expanded)]]">
+ <button disabled="[[disabled]]" aria-label$="[[alt]]"
+ aria-pressed$="[[getAriaPressed_(expanded)]]"
+ tabindex$="[[tabIndex]]">
+ </button>
+ </paper-icon-button-light>
</template>
<script src="cr_expand_button.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js
index d7729d583b1..2637e07e36d 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js
@@ -77,8 +77,9 @@ Polymer({
* @private
*/
onKeyPress_: function(event) {
- if (event.key == ' ' || event.key == 'Enter')
+ if (event.key == ' ' || event.key == 'Enter') {
this.updateRippleHoldDown_(true);
+ }
},
/** @private */
@@ -100,8 +101,9 @@ Polymer({
// If this event originated from a pointer, then |ripple.holdDown| should
// preemptively be set to false to allow ripple to animate.
- if (this.fromPointer_)
+ if (this.fromPointer_) {
this.updateRippleHoldDown_(false);
+ }
this.fromPointer_ = false;
},
diff --git a/chromium/ui/webui/resources/cr_elements/cr_icons_css.html b/chromium/ui/webui/resources/cr_elements/cr_icons_css.html
index 6c346a380e8..07e27e492a8 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_icons_css.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_icons_css.html
@@ -9,8 +9,12 @@
}
paper-icon-button-light paper-ripple {
- color: currentColor;
- opacity: 0.6;
+ opacity: 0.6; /* TODO(dbeam): seems like ripples are too light. */
+ }
+
+ :host-context([dark]) paper-icon-button-light paper-ripple {
+ --paper-ripple-opacity: .4;
+ opacity: 1;
}
paper-icon-button-light button {
@@ -30,81 +34,133 @@
}
:-webkit-any(paper-icon-button-light, .cr-icon).no-overlap {
- margin-left: 0;
- margin-right: 0;
+ margin-inline-end: 0;
+ margin-inline-start: 0;
}
:-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-back {
background-image: url(../images/icon_arrow_back.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-back {
+ background-image: url(../images/dark/icon_arrow_back.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel {
background-image: url(../images/icon_cancel.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel {
+ background-image: url(../images/dark/icon_cancel.svg);
+ }
- :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel-toolbar {
- background-image: url(../images/icon_cancel_toolbar.svg);
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-cancel {
+ background-image: url(../images/icon_toolbar_cancel.svg);
+ }
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-cancel {
+ background-image: url(../images/dark/icon_toolbar_cancel.svg);
}
:-webkit-any(paper-icon-button-light, .cr-icon).icon-clear {
background-image: url(../images/icon_clear.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-clear {
+ background-image: url(../images/dark/icon_clear.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-gray {
background-image: url(../images/icon_delete_gray.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-gray {
+ background-image: url(../images/dark/icon_delete_gray.svg);
+ }
- :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-white {
- background-image: url(../images/icon_delete_white.svg);
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-picture-delete {
+ background-image: url(../images/icon_picture_delete.svg);
+ }
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-picture-delete {
+ background-image: url(../images/dark/icon_picture_delete.svg);
}
:-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-less {
background-image: url(../images/icon_expand_less.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-less {
+ background-image: url(../images/dark/icon_expand_less.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-more {
background-image: url(../images/icon_expand_more.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-more {
+ background-image: url(../images/dark/icon_expand_more.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-external {
background-image: url(../images/open_in_new.svg);
}
+ /* Open in new is the same for light and dark mode. */
- :-webkit-any(paper-icon-button-light, .cr-icon).icon-menu-white {
- background-image: url(../images/icon_menu_white.svg);
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-menu {
+ background-image: url(../images/icon_toolbar_menu.svg);
+ }
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-menu {
+ background-image: url(../images/dark/icon_toolbar_menu.svg);
}
:-webkit-any(paper-icon-button-light, .cr-icon).icon-more-vert {
background-image: url(../images/icon_more_vert.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-more-vert {
+ background-image: url(../images/dark/icon_more_vert.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-refresh {
background-image: url(../images/icon_refresh.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-refresh {
+ background-image: url(../images/dark/icon_refresh.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-settings {
background-image: url(../images/icon_settings.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-settings {
+ background-image: url(../images/dark/icon_settings.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-search {
background-image: url(../images/icon_search.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-search {
+ background-image: url(../images/dark/icon_search.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-dropdown {
background-image: url(../images/icon_arrow_dropdown.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-dropdown {
+ background-image: url(../images/dark/icon_arrow_dropdown.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).subpage-arrow {
background-image: url(../images/arrow_right.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).subpage-arrow {
+ background-image: url(../images/dark/arrow_right.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility {
background-image: url(../images/icon_visibility.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility {
+ background-image: url(../images/dark/icon_visibility.svg);
+ }
:-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility-off {
background-image: url(../images/icon_visibility_off.svg);
}
+ :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility-off {
+ background-image: url(../images/dark/icon_visibility_off.svg);
+ }
</style>
</template>
</dom-module>
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 f66e06127a2..2745ab5dd79 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
@@ -48,8 +48,7 @@
}
#input::placeholder {
- color: var(--cr-input-placeholder-color,
- var(--google-grey-refresh-700));
+ color: var(--cr-input-placeholder-color);
}
:host([invalid]) #input {
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 a14a8ba95e1..6549129601a 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
@@ -157,13 +157,15 @@ Polymer({
/** @override */
attached: function() {
const ariaLabel = this.ariaLabel || this.label || this.placeholder;
- if (ariaLabel)
+ if (ariaLabel) {
this.inputElement.setAttribute('aria-label', ariaLabel);
+ }
// Run this for the first time in attached instead of in disabledChanged_
// since this.tabindex might not be set yet then.
- if (this.disabled)
+ if (this.disabled) {
this.reconcileTabindex_();
+ }
},
/** @return {!HTMLInputElement} */
@@ -179,8 +181,9 @@ Polymer({
// Don't change tabindex until after finished attaching, since this.tabindex
// might not be intialized yet.
- if (previous !== undefined)
+ if (previous !== undefined) {
this.reconcileTabindex_();
+ }
},
/**
@@ -205,16 +208,18 @@ Polymer({
* @private
*/
placeholderChanged_: function() {
- if (this.placeholder || this.placeholder == '')
+ if (this.placeholder || this.placeholder == '') {
this.inputElement.setAttribute('placeholder', this.placeholder);
- else
+ } else {
this.inputElement.removeAttribute('placeholder');
+ }
},
/** @private */
onFocus_: function() {
- if (!this.focusInput_())
+ if (!this.focusInput_()) {
return;
+ }
// Always select the <input> element on focus. TODO(stevenjb/scottchen):
// Native <input> elements only do this for keyboard focus, not when
// focus() is called directly. Fix this? https://crbug.com/882612.
@@ -226,8 +231,9 @@ Polymer({
* @private
*/
focusInput_: function() {
- if (this.shadowRoot.activeElement == this.inputElement)
+ if (this.shadowRoot.activeElement == this.inputElement) {
return false;
+ }
this.inputElement.focus();
return true;
},
@@ -235,8 +241,9 @@ Polymer({
/** @private */
recordAndUnsetTabIndex_: function() {
// Don't change originalTabIndex_ if it just got changed.
- if (this.originalTabIndex_ === null)
+ if (this.originalTabIndex_ === null) {
this.originalTabIndex_ = this.tabindex;
+ }
this.tabindex = null;
},
@@ -255,8 +262,9 @@ Polymer({
*/
onPointerDown_: function(e) {
// Don't need to manipulate tabindex if cr-input is already disabled.
- if (this.disabled)
+ if (this.disabled) {
return;
+ }
// Should not mess with tabindex when <input> is clicked, otherwise <input>
// will lose and regain focus, and replay the focus animation.
@@ -264,8 +272,9 @@ Polymer({
this.recordAndUnsetTabIndex_();
setTimeout(() => {
// Restore tabindex, unless disabled in the same cycle as pointerdown.
- if (!this.disabled)
+ if (!this.disabled) {
this.restoreTabIndex_();
+ }
}, 0);
}
},
@@ -280,8 +289,9 @@ Polymer({
* @private
*/
onInputKeydown_: function(e) {
- if (e.shiftKey && e.key === 'Tab')
+ if (e.shiftKey && e.key === 'Tab') {
this.focus();
+ }
},
/**
@@ -290,10 +300,12 @@ Polymer({
* @private
*/
onValueChanged_: function(newValue, oldValue) {
- if (!newValue && !oldValue)
+ if (!newValue && !oldValue) {
return;
- if (this.autoValidate)
+ }
+ if (this.autoValidate) {
this.validate();
+ }
},
/**
diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
index a78334b5223..9cf635dc6f8 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
@@ -8,14 +8,25 @@
<template>
<style>
:host {
+ --cr-input-background-color: var(--google-grey-refresh-100);
+ --cr-input-color: var(--google-grey-900);
--cr-input-error-color: var(--google-red-600);
--cr-input-focus-color: var(--google-blue-600);
+ --cr-input-placeholder-color: var(--google-grey-refresh-700);
display: block;
/* Avoid showing outline when focus() programmatically called multiple
times in a row. */
outline: none;
}
+ :host-context([dark]) {
+ --cr-input-background-color: rgba(0, 0, 0, .3);
+ --cr-input-color: var(--google-grey-refresh-500);
+ --cr-input-error-color: var(--google-red-refresh-300);
+ --cr-input-focus-color: var(--google-blue-refresh-300);
+ --cr-input-placeholder-color: var(--google-grey-refresh-500);
+ }
+
/* Label styling below. */
#label {
@apply --cr-form-field-label;
@@ -36,8 +47,7 @@
}
#inner-input-container {
- background-color: var(--cr-input-background-color,
- var(--google-grey-refresh-100));
+ background-color: var(--cr-input-background-color);
box-sizing: border-box;
padding: 0;
@@ -46,12 +56,11 @@
#input {
-webkit-appearance: none;
- background-color: var(--cr-input-background-color,
- var(--google-grey-refresh-100));
+ background-color: var(--cr-input-background-color);
border: none;
box-sizing: border-box;
caret-color: var(--cr-input-focus-color);
- color: var(--cr-input-color, var(--google-grey-900));
+ color: var(--cr-input-color);
font-family: inherit;
font-size: inherit;
line-height: inherit;
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 43db9123f86..6c7df6f7bab 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
@@ -35,8 +35,9 @@ Polymer({
* @return {Element} Child element which has been stamped into the DOM tree.
*/
get: function() {
- if (!this.child_)
+ if (!this.child_) {
this.render_();
+ }
return this.child_;
},
@@ -51,8 +52,9 @@ Polymer({
/** @private */
render_: function() {
const template = this.getContentChildren()[0];
- if (!this.ctor)
+ if (!this.ctor) {
this.templatize(template);
+ }
const parentNode = this.parentNode;
if (parentNode && !this.child_) {
this.instance_ = this.stamp({});
@@ -67,8 +69,9 @@ Polymer({
* @param {Object} value
*/
_forwardParentProp: function(prop, value) {
- if (this.child_)
+ if (this.child_) {
this.child_._templateInstance[prop] = value;
+ }
},
/**
@@ -77,8 +80,9 @@ Polymer({
* @param {Object} value
*/
_forwardParentPath: function(path, value) {
- if (this.child_)
+ if (this.child_) {
this.child_._templateInstance.notifyPath(path, value, true);
+ }
},
/**
@@ -86,7 +90,8 @@ Polymer({
* @param {Object} value
*/
_forwardHostPropV2: function(prop, value) {
- if (this.instance_)
+ if (this.instance_) {
this.instance_.forwardHostProp(prop, value);
+ }
},
});
diff --git a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html
index 2b12b55b573..c83de0a3240 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html
@@ -62,20 +62,17 @@
#labelWrapper {
flex: 1;
flex-basis: 0.000000001px;
+ padding-bottom: var(--cr-section-vertical-padding);
+ padding-top: var(--cr-section-vertical-padding);
text-align: start;
}
#outer {
align-items: center;
display: flex;
- min-height: var(--cr-section-two-line-min-height);
width: 100%;
}
- #outer[noSubLabel] {
- min-height: var(--cr-section-min-height);
- }
-
paper-ripple {
opacity: 0.6;
}
@@ -84,7 +81,10 @@
@apply --cr-secondary-text;
}
</style>
- <button disabled="[[disabled]]">
+ <button
+ aria-describedby$="[[ariaDescribedBy_]]"
+ aria-label$="[[label]]"
+ disabled="[[disabled]]">
<div id="outer" noSubLabel$="[[!subLabel]]">
<iron-icon id="startIcon" icon="[[startIcon]]" hidden="[[!startIcon]]"
aria-hidden="true">
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 2ccbc9ad1a3..e619bfcd042 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
@@ -32,12 +32,16 @@ Polymer({
type: String,
/* Value used for noSubLabel attribute. */
value: '',
+ observer: 'onSubLabelChange_',
},
disabled: {
type: Boolean,
reflectToAttribute: true,
},
+
+ /** @private {string|undefined} */
+ ariaDescribedBy_: String,
},
listeners: {
@@ -68,4 +72,9 @@ Polymer({
ripple.classList.add('circle');
return ripple;
},
+
+ /** @private */
+ onSubLabelChange_: function() {
+ this.ariaDescribedBy_ = this.subLabel ? 'subLabel' : undefined;
+ },
});
diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js
index ea4098ddd68..e5b4619fb7b 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js
@@ -70,8 +70,9 @@ Polymer({
*/
onAvatarTap_: function(e) {
// Manual selection for profile creation
- if (this.selectedAvatarElement_)
+ if (this.selectedAvatarElement_) {
this.selectedAvatarElement_.classList.remove('iron-selected');
+ }
this.selectedAvatarElement_ = /** @type {!HTMLElement} */ (e.target);
this.selectedAvatarElement_.classList.add('iron-selected');
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 444e458585f..370513ef7f9 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
@@ -36,8 +36,9 @@ Polymer({
case 'ArrowLeft':
case 'ArrowRight':
// Ignores keys likely to be browse shortcuts (like Alt+Left for back).
- if (this.ignoreModifiedKeyEvents && hasKeyModifiers(e))
+ if (this.ignoreModifiedKeyEvents && hasKeyModifiers(e)) {
return;
+ }
this.moveFocusRow_(items, e.key);
e.preventDefault();
@@ -73,18 +74,21 @@ Polymer({
if (direction == 'ArrowDown' || direction == 'ArrowUp') {
for (let i = offset; Math.abs(i) <= rows; i += offset) {
nextItem = items[(focusIndex + i * rowSize + gridSize) % gridSize];
- if (nextItem)
+ if (nextItem) {
break;
+ }
// This codepath can be hit when |gridSize| is larger than
// |items.length|, which means that there are empty grid spots at the
// end.
}
} else {
- if (style.direction == 'rtl')
+ if (style.direction == 'rtl') {
offset *= -1;
+ }
let nextIndex = (focusIndex + offset) % items.length;
- if (nextIndex < 0)
+ 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 c08463e25ae..4bd6021d5da 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
@@ -59,8 +59,9 @@ const CrRadioButtonBehaviorImpl = {
* @private
*/
disabledChanged_: function(current, previous) {
- if (previous === undefined && !this.disabled)
+ if (previous === undefined && !this.disabled) {
return;
+ }
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
},
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 4ff9b856567..b344aa5296b 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
@@ -8,10 +8,14 @@
<template>
<style>
:host {
+ --cr-radio-button-checked-color: var(--google-blue-600);
+ --cr-radio-button-checked-ripple-color:
+ rgba(var(--google-blue-600-rgb), .2);
--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);
+ --cr-radio-button-unchecked-ripple-color:
+ rgba(var(--google-grey-600-rgb), .15);
--ink-to-circle: calc((var(--cr-radio-button-ink-size) -
var(--cr-radio-button-size)) / 2);
@@ -21,6 +25,15 @@
outline: none;
}
+ :host-context([dark]) {
+ --cr-radio-button-checked-color: var(--google-blue-refresh-300);
+ --cr-radio-button-checked-ripple-color:
+ rgba(var(--google-blue-refresh-300-rgb), .4);
+ --cr-radio-button-unchecked-color: var(--google-grey-refresh-500);
+ --cr-radio-button-unchecked-ripple-color:
+ rgba(var(--google-grey-refresh-300-rgb), .4);
+ }
+
:host([disabled]) {
opacity: var(--cr-disabled-opacity);
/* Disable pointer events for this whole element, as outer on-tap gets
@@ -87,8 +100,8 @@
}
paper-ripple {
- --paper-ripple-opacity: 0.15;
- color: var(--google-grey-600);
+ --paper-ripple-opacity: 1; /* Opacity in each color's alpha. */
+ color: var(--cr-radio-button-unchecked-ripple-color);
height: var(--cr-radio-button-ink-size);
left: calc(-1 * var(--ink-to-circle));
pointer-events: none;
@@ -104,8 +117,7 @@
}
:host([checked]) paper-ripple {
- --paper-ripple-opacity: 0.2;
- color: var(--google-blue-600);
+ color: var(--cr-radio-button-checked-ripple-color);
}
</style>
</template>
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
index 328f071d894..12f2edccf26 100644
--- 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
@@ -76,7 +76,7 @@
/** @override */
attached: function() {
- this.isRtl_ = this.matches(':host-context([dir=rtl]) cr-slider');
+ this.isRtl_ = this.matches(':host-context([dir=rtl]) cr-radio-group');
this.deltaKeyMap_ = new Map([
['ArrowDown', 1],
['ArrowLeft', this.isRtl_ ? 1 : -1],
@@ -92,19 +92,20 @@
// dom-if.
// TODO(crbug.com/738611): After migration to Polymer 2, remove Polymer 1
// references.
- if (Polymer.DomIf)
+ if (Polymer.DomIf) {
this.$$('slot').addEventListener('slotchange', this.populateBound_);
- else
+ } else {
this.observer_ = Polymer.dom(this).observeNodes(this.populateBound_);
+ }
this.populate_();
},
/** @override */
detached: function() {
- if (Polymer.DomIf)
+ if (Polymer.DomIf) {
this.$$('slot').removeEventListener('slotchange', this.populateBound_);
- else if (this.observer_) {
+ } else if (this.observer_) {
Polymer.dom(this).unobserveNodes(
/** @type {!PolymerDomApi.ObserveHandle} */ (this.observer_));
}
@@ -113,13 +114,15 @@
/** @override */
focus: function() {
- if (this.disabled || !this.buttons_)
+ if (this.disabled || !this.buttons_) {
return;
+ }
const radio =
this.buttons_.find(radio => radio.getAttribute('tabindex') == '0');
- if (radio)
+ if (radio) {
radio.focus();
+ }
},
/**
@@ -127,15 +130,18 @@
* @private
*/
onKeyDown_: function(event) {
- if (this.disabled)
+ if (this.disabled) {
return;
+ }
- if (event.ctrlKey || event.shiftKey || event.metaKey || event.altKey)
+ if (event.ctrlKey || event.shiftKey || event.metaKey || event.altKey) {
return;
+ }
const targetElement = /** @type {!Element} */ (event.target);
- if (!this.buttons_.includes(targetElement))
+ if (!this.buttons_.includes(targetElement)) {
return;
+ }
if (event.key == ' ' || event.key == 'Enter') {
event.preventDefault();
@@ -144,8 +150,9 @@
}
const enabledRadios = this.buttons_.filter(isEnabled);
- if (enabledRadios.length == 0)
+ if (enabledRadios.length == 0) {
return;
+ }
let selectedIndex;
const max = enabledRadios.length - 1;
@@ -187,12 +194,14 @@
*/
onClick_: function(event) {
const path = event.composedPath();
- if (path.some(target => /^a$/i.test(target.tagName)))
+ 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))
+ if (target && this.buttons_.includes(target)) {
this.select_(/** @type {!Element} */ (target));
+ }
},
/** @private */
@@ -219,18 +228,21 @@
* @private
*/
select_: function(button) {
- if (!isEnabled(button))
+ if (!isEnabled(button)) {
return;
+ }
const name = `${button.name}`;
- if (this.selected != name)
+ if (this.selected != name) {
this.selected = name;
+ }
},
/** @private */
update_: function() {
- if (!this.buttons_)
+ if (!this.buttons_) {
return;
+ }
let noneMadeFocusable = true;
this.buttons_.forEach(radio => {
radio.checked = this.selected != undefined &&
@@ -242,8 +254,9 @@
});
if (noneMadeFocusable && !this.disabled) {
const focusable = this.buttons_.find(isEnabled);
- if (focusable)
+ 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 b27a0f80b54..31d7934d36b 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
@@ -62,8 +62,9 @@ const CrScrollableBehavior = {
},
detached: function() {
- if (this.intervalId_ !== null)
+ if (this.intervalId_ !== null) {
clearInterval(this.intervalId_);
+ }
},
/**
@@ -72,14 +73,16 @@ const CrScrollableBehavior = {
* containers are resized correctly.
*/
updateScrollableContents: function() {
- if (this.intervalId_ !== null)
- return; // notifyResize is already in progress.
+ if (this.intervalId_ !== null) {
+ return;
+ } // notifyResize is already in progress.
this.requestUpdateScroll();
let nodeList = this.root.querySelectorAll('[scrollable] iron-list');
- if (!nodeList.length)
+ if (!nodeList.length) {
return;
+ }
// Use setInterval to avoid initial render / sizing issues.
this.intervalId_ = window.setInterval(function() {
@@ -110,8 +113,9 @@ const CrScrollableBehavior = {
requestUpdateScroll: function() {
requestAnimationFrame(function() {
const scrollableElements = this.root.querySelectorAll('[scrollable]');
- for (let i = 0; i < scrollableElements.length; i++)
+ for (let i = 0; i < scrollableElements.length; i++) {
this.updateScroll_(/** @type {!HTMLElement} */ (scrollableElements[i]));
+ }
}.bind(this));
},
@@ -130,8 +134,9 @@ const CrScrollableBehavior = {
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)
+ if (scrollTop != 0) {
list.scroll(0, scrollTop);
+ }
});
},
diff --git a/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn
index 481c4e60be4..bcfe47c11da 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
js_type_check("closure_compile") {
deps = [
+ ":cr_search_field",
":cr_search_field_behavior",
]
}
@@ -15,3 +16,12 @@ js_library("cr_search_field_behavior") {
"//ui/webui/resources/js:assert",
]
}
+
+js_library("cr_search_field") {
+ deps = [
+ ":cr_search_field_behavior",
+ "//third_party/polymer/v1_0/components-chromium/paper-icon-button:paper-icon-button-extracted",
+ "//ui/webui/resources/cr_elements/cr_input:cr_input",
+ "//ui/webui/resources/js:assert",
+ ]
+}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html b/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html
new file mode 100644
index 00000000000..d0ded7bc785
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html
@@ -0,0 +1,95 @@
+<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/icons.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="cr_search_field_behavior.html">
+
+<dom-module id="cr-search-field">
+ <template>
+ <style include="cr-shared-style">
+ :host {
+ display: flex;
+ user-select: none;
+ }
+
+ #searchIcon {
+ align-self: center;
+ height: 16px;
+ padding: 4px;
+ vertical-align: middle;
+ width: 16px;
+ }
+
+ cr-input {
+ --cr-input-background-color: white;
+ --cr-input-row-container: {
+ height: 100%;
+ }
+ --cr-input-container: {
+ border-radius: 0;
+ height: 100%;
+ }
+ --cr-input-inner-container: {
+ height: 100%;
+ }
+ --cr-input-error-display: none;
+ --cr-input-input: {
+ height: 100%;
+ border-bottom: 1px solid var(--google-grey-900);
+ }
+ --cr-input-padding-end: 0;
+ --cr-input-padding-start: 0;
+ --cr-input-padding-bottom: 2px;
+ --cr-input-padding-top: 2px;
+ align-self: stretch;
+ display: block;
+ vertical-align: middle;
+ width: 160px; /* Special width for search input. */
+ }
+
+ :host([has-search-text]) cr-input {
+ --cr-input-padding-end: 20px;
+ }
+
+ #searchInput {
+ font-size: 92.3076923%; /* To 12px from 13px. */
+ min-height: 24px;
+ }
+
+ #searchInput {
+ color: var(--cr-primary-text-color);
+ }
+
+ #clearSearchContainer {
+ /* A 16px icon that fits on the input line. */
+ background-size: 16px;
+ height: 24px;
+ margin-inline-end: -4px;
+ margin-inline-start: 4px;
+ position: absolute;
+ right: 0;
+ width: 24px;
+ }
+
+ :host-context([dir='rtl']) #clearSearchContainer {
+ left: 0;
+ right: auto;
+ }
+ </style>
+ <iron-icon id="searchIcon" icon="cr:search"></iron-icon>
+ <cr-input id="searchInput" on-search="onSearchTermSearch"
+ on-input="onSearchTermInput" aria-label$="[[label]]" type="search"
+ autofocus="[[autofocus]]" placeholder="[[label]]" spellcheck="false">
+ <paper-icon-button-light id="clearSearchContainer" class="icon-cancel"
+ hidden$="[[!hasSearchText]]" slot="suffix">
+ <button id="clearSearch" on-click="onTapClear_" title="[[clearLabel]]">
+ </button>
+ </paper-icon-button-light>
+ </cr-input>
+ </template>
+ <script src="cr_search_field.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.js b/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.js
new file mode 100644
index 00000000000..9317894c107
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.js
@@ -0,0 +1,33 @@
+// 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.
+
+/**
+ * @fileoverview
+ * 'cr-search-field' is a simple implementation of a polymer component that
+ * uses CrSearchFieldBehavior.
+ */
+
+Polymer({
+ is: 'cr-search-field',
+
+ behaviors: [CrSearchFieldBehavior],
+
+ properties: {
+ autofocus: {
+ type: Boolean,
+ value: false,
+ },
+ },
+
+ /** @return {!CrInputElement} */
+ getSearchInput: function() {
+ return this.$.searchInput;
+ },
+
+ /** @private */
+ onTapClear_: function() {
+ this.setValue('');
+ this.$.searchInput.focus();
+ },
+}); \ No newline at end of file
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 929058b4344..f0235c90292 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
@@ -64,8 +64,9 @@ const CrSearchFieldBehavior = {
/** @private */
scheduleSearch_: function() {
- if (this.searchDelayTimer_ >= 0)
+ if (this.searchDelayTimer_ >= 0) {
clearTimeout(this.searchDelayTimer_);
+ }
// Dispatch 'search' event after:
// 0ms if the value is empty
// 500ms if the value length is 1
@@ -106,12 +107,14 @@ const CrSearchFieldBehavior = {
*/
onValueChanged_: function(newValue, noEvent) {
const effectiveValue = newValue.replace(/\s+/g, ' ');
- if (effectiveValue == this.lastValue_)
+ if (effectiveValue == this.lastValue_) {
return;
+ }
this.lastValue_ = effectiveValue;
- if (!noEvent)
+ if (!noEvent) {
this.fire('search-changed', effectiveValue);
+ }
},
};
diff --git a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
index 209dc714d37..171c6f528b8 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
@@ -2,18 +2,20 @@
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html">
<dom-module id="cr-searchable-drop-down">
<template>
<style>
- cr-input {
+ :host(:not([error-message-allowed])) cr-input {
--cr-input-error-display: none;
}
iron-dropdown,
cr-input {
- width: var(--cr-searchable-drop-down-width, 270px);
+ width: var(--cr-searchable-drop-down-width,
+ var(--cr-default-input-max-width));
}
iron-dropdown {
@@ -50,7 +52,9 @@
explicitly used. -->
<cr-input label="[[label]]" on-click="onClick_" value="[[value]]"
on-input="onInput_" id="search" autofocus="[[autofocus]]"
- placeholder="[[placeholder]]">
+ placeholder="[[placeholder]]"
+ error-message="[[getErrorMessage_(errorMessage, errorMessageAllowed)]]"
+ invalid="[[shouldShowErrorMessage_(errorMessage, errorMessageAllowed)]]">
</cr-input>
<iron-dropdown horizontal-align="left" vertical-align="top"
vertical-offset="52">
diff --git a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
index e7e94edb832..443217893c2 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
@@ -20,6 +20,22 @@ Polymer({
reflectToAttribute: true,
},
+ /**
+ * Whether space should be left below the text field to display an error
+ * message. Must be true for |errorMessage| to be displayed.
+ */
+ errorMessageAllowed: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ },
+
+ /**
+ * When |errorMessage| is set, the text field is highlighted red and
+ * |errorMessage| is displayed beneath it.
+ */
+ errorMessage: String,
+
placeholder: String,
/** @type {!Array<string>} */
@@ -71,10 +87,35 @@ Polymer({
/** @private */
filterItems_: function(searchTerm) {
- if (!searchTerm)
+ if (!searchTerm) {
return null;
+ }
return function(item) {
return item.toLowerCase().includes(searchTerm.toLowerCase());
};
},
+
+ /**
+ * @param {string} errorMessage
+ * @param {boolean} errorMessageAllowed
+ * @return {boolean}
+ * @private
+ */
+ shouldShowErrorMessage_: function(errorMessage, errorMessageAllowed) {
+ return !!this.getErrorMessage_(errorMessage, errorMessageAllowed);
+ },
+
+ /**
+ * @param {string} errorMessage
+ * @param {boolean} errorMessageAllowed
+ * @return {string}
+ * @private
+ */
+ getErrorMessage_: function(errorMessage, errorMessageAllowed) {
+ if (!errorMessageAllowed) {
+ return '';
+ }
+ return errorMessage;
+ },
+
}); \ No newline at end of file
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 7f6bcd2d7bd..3ba1e9538e5 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
@@ -12,8 +12,10 @@
<style include="cr-hidden-style">
:host {
--cr-slider-bar-height: 2px;
+ --cr-slider-position-transition: 80ms ease;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
cursor: default;
+ outline: none;
user-select: none;
}
@@ -36,7 +38,8 @@
}
#barContainer {
- border-top-color: var(--google-blue-600-opacity-24);
+ border-top-color: var(--cr-slider-container-color,
+ rgba(var(--google-blue-600-rgb), .24));
height: var(--cr-slider-bar-height);
margin: 0 16px;
position: absolute;
@@ -50,15 +53,12 @@
#bar {
border-top-color: var(--cr-slider-active-color, var(--google-blue-600));
- left: 0;
position: absolute;
- transition: width 80ms ease;
width: 0;
}
- :host([is-rtl_]) #bar {
- left: initial;
- right: 0;
+ :host([transiting_]) #bar {
+ transition: width var(--cr-slider-position-transition);
}
#knobContainer {
@@ -77,12 +77,15 @@
margin-inline-start: 0;
outline: none;
position: absolute;
- transition: margin-inline-start 80ms ease;
width: 10px;
}
+ :host([transiting_]) #knob {
+ transition: margin-inline-start var(--cr-slider-position-transition);
+ }
+
paper-ripple {
- color: var(--google-blue-600);
+ color: var(--cr-slider-knob-color, var(--google-blue-600));
height: 32px;
left: -11px;
pointer-events: none;
@@ -154,16 +157,19 @@
line-height: 1.5em;
padding: 0 8px;
position: absolute;
- transition: margin-inline-start 80ms ease;
white-space: nowrap;
}
+ :host([transiting_]) #label {
+ transition: margin-inline-start var(--cr-slider-position-transition);
+ }
+
:host([disabled_]) {
pointer-events: none;
}
:host([disabled_]) #barContainer {
- border-top-color: var(--google-grey-600-opacity-24);
+ border-top-color: rgba(var(--google-grey-600-rgb), .24);
}
:host([disabled_]) #bar {
@@ -190,13 +196,14 @@
<div id="bar"></div>
<div id="markers" hidden$="[[!markerCount]]">
<template is="dom-repeat" items="[[getMarkers_(markerCount)]]">
- <div class$="[[getMarkerClass_(index, immediateValue_, min, max,
+ <div class$="[[getMarkerClass_(index, value, min, max,
markerCount)]]"></div>
</template>
</div>
</div>
<div id="knobContainer">
- <div id="knob" tabindex="0"></div>
+ <div id="knob" on-transitionend="onKnobTransitionEnd_"
+ on-keydown="onKnobKeydown_"></div>
</div>
<div id="labelContainer" aria-label="[[label_]]">
<div id="label">[[label_]]</div>
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 c2671d9b700..aeaa6c0b605 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
@@ -34,6 +34,12 @@ cr_slider.SliderTick;
return Math.min(max, Math.max(min, value));
}
+ /**
+ * The following are the events emitted from cr-slider.
+ *
+ * cr-slider-value-changed: fired when updating slider via the UI.
+ * dragging-changed: fired on pointer down and on pointer up.
+ */
Polymer({
is: 'cr-slider',
@@ -109,28 +115,6 @@ cr_slider.SliderTick;
value: {
type: Number,
value: 0,
- notify: true,
- observer: 'onValueChanged_',
- },
-
- /**
- * If true, |value| is updated while dragging happens. If false, |value|
- * is updated only once, when drag gesture finishes.
- */
- updateValueInstantly: {
- type: Boolean,
- value: true,
- },
-
- /**
- * |immediateValue_| has the most up-to-date value and is used to render
- * the slider UI. When dragging, |immediateValue_| is always updated, and
- * |value| is updated at least once when dragging is stopped.
- * @private
- */
- immediateValue_: {
- type: Number,
- value: 0,
},
/** @private */
@@ -153,6 +137,20 @@ cr_slider.SliderTick;
value: false,
reflectToAttribute: true,
},
+
+ /**
+ * |transiting_| is set to true when bar is touched or clicked. This
+ * triggers a single position transition effect to take place for the
+ * knob, bar and label. When the transition is complete, |transiting_| is
+ * set to false resulting in no transition effect during dragging, manual
+ * value updates and keyboard events.
+ * @private
+ */
+ transiting_: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ },
},
hostAttributes: {
@@ -161,8 +159,8 @@ cr_slider.SliderTick;
observers: [
'onTicksChanged_(ticks.*)',
- 'updateLabelAndAria_(immediateValue_, min, max)',
- 'updateKnobAndBar_(immediateValue_, min, max)',
+ 'updateLabelAndAria_(value, min, max)',
+ 'updateKnobAndBar_(value, min, max)',
],
listeners: {
@@ -217,7 +215,7 @@ cr_slider.SliderTick;
* @private
*/
getMarkerClass_: function(index) {
- const currentStep = (this.markerCount - 1) * this.getRatio_();
+ const currentStep = (this.markerCount - 1) * this.getRatio();
return index < currentStep ? 'active-marker' : 'inactive-marker';
},
@@ -227,21 +225,9 @@ cr_slider.SliderTick;
* This is a helper function used to calculate the bar width, knob location
* and label location.
* @return {number}
- * @private
*/
- getRatio_: function() {
- return (this.immediateValue_ - this.min) / (this.max - this.min);
- },
-
- /** @private */
- ensureValidValue_: function() {
- if (this.immediateValue_ == undefined || this.value == undefined)
- return;
- let validValue = clamp(this.min, this.max, this.immediateValue_);
- validValue = this.snaps ? Math.round(validValue) : validValue;
- this.immediateValue_ = validValue;
- if (!this.dragging || this.updateValueInstantly)
- this.value = validValue;
+ getRatio: function() {
+ return (this.value - this.min) / (this.max - this.min);
},
/**
@@ -250,9 +236,6 @@ cr_slider.SliderTick;
* @private
*/
stopDragging_: function(pointerId) {
- // 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;
@@ -270,13 +253,19 @@ cr_slider.SliderTick;
/** @private */
onDisabledChanged_: function() {
- this.$.knob.setAttribute('tabindex', this.disabled_ ? '-1' : '0');
+ this.setAttribute('tabindex', this.disabled_ ? -1 : 0);
+ this.$.knob.setAttribute('tabindex', this.disabled_ ? -1 : 0);
this.blur();
},
/** @private */
onFocus_: function() {
this.holdDown_ = true;
+
+ if (this.shadowRoot.activeElement == this.$.knob) {
+ return;
+ }
+ this.$.knob.focus();
},
/** @private */
@@ -289,32 +278,57 @@ cr_slider.SliderTick;
* @private
*/
onKeyDown_: function(event) {
- if (this.disabled_ || this.noKeybindings)
+ if (this.disabled_ || this.noKeybindings) {
return;
+ }
- if (event.metaKey || event.shiftKey || event.altKey || event.ctrlKey)
+ if (event.metaKey || event.shiftKey || event.altKey || event.ctrlKey) {
return;
+ }
- let handled = true;
+ /** @type {number|undefined} */
+ let newValue;
if (event.key == 'Home') {
- this.immediateValue_ = this.min;
+ newValue = this.min;
} else if (event.key == 'End') {
- this.immediateValue_ = this.max;
+ newValue = this.max;
} else if (this.deltaKeyMap_.has(event.key)) {
- const newValue = this.value + this.deltaKeyMap_.get(event.key);
- this.immediateValue_ = clamp(this.min, this.max, newValue);
- } else {
- handled = false;
+ newValue = this.value + this.deltaKeyMap_.get(event.key);
}
- if (handled) {
- this.value = this.immediateValue_;
- event.preventDefault();
- event.stopPropagation();
- setTimeout(() => {
- this.holdDown_ = true;
- });
+ if (newValue == undefined) {
+ return;
}
+
+ if (this.updateValue_(newValue)) {
+ this.fire('cr-slider-value-changed');
+ }
+ event.preventDefault();
+ event.stopPropagation();
+ setTimeout(() => {
+ this.holdDown_ = true;
+ });
+ },
+
+ /**
+ * This code is taken from cr-input. See https://crbug.com/832177#c31 for
+ * the CL that handles escaping focus from the shadow DOM.
+ * TODO(aee): see if a common behavior can be extracted from cr-slider and
+ * cr-input with regards to focusing an element in the shadow DOM and
+ * also being a focusable component. It may be useful for other
+ * components.
+ * @param {!KeyboardEvent} e
+ * @private
+ */
+ onKnobKeydown_: function(e) {
+ if (e.shiftKey && e.key === 'Tab') {
+ this.focus();
+ }
+ },
+
+ /** @private */
+ onKnobTransitionEnd_: function() {
+ this.transiting_ = false;
},
/**
@@ -324,10 +338,13 @@ 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.transiting_ = true;
this.updateValueFromClientX_(event.clientX);
// If there is a ripple animation in progress, setTimeout will hold off on
// updating |holdDown_|.
@@ -353,41 +370,25 @@ cr_slider.SliderTick;
this.draggingEventTracker_.add(this, 'pointerdown', stopDragging);
this.draggingEventTracker_.add(this, 'pointerup', stopDragging);
this.draggingEventTracker_.add(this, 'keydown', e => {
- if (e.key == 'Escape' || e.key == 'Tab')
+ if (e.key == 'Escape' || e.key == 'Tab') {
stopDragging();
+ }
});
},
/** @private */
onTicksChanged_: function() {
- if (this.ticks.length == 0) {
- this.snaps = false;
- } else if (this.ticks.length > 1) {
+ if (this.ticks.length > 1) {
this.snaps = true;
this.max = this.ticks.length - 1;
this.min = 0;
}
- this.ensureValidValue_();
- this.updateLabelAndAria_();
- },
-
- /**
- * Update |immediateValue_| which is used for rendering when |value| is
- * updated either programmatically or from a keyboard input or a mouse drag
- * (when |updateValueInstantly| is true).
- * @private
- */
- onValueChanged_: function() {
- if (this.immediateValue_ == this.value)
- return;
-
- this.immediateValue_ = this.value;
- this.ensureValidValue_();
+ this.updateValue_(this.value);
},
/** @private */
updateKnobAndBar_: function() {
- const percent = `${this.getRatio_() * 100}%`;
+ const percent = `${this.getRatio() * 100}%`;
this.$.bar.style.width = percent;
this.$.knob.style.marginInlineStart = percent;
},
@@ -395,7 +396,7 @@ cr_slider.SliderTick;
/** @private */
updateLabelAndAria_: function() {
const ticks = this.ticks;
- const index = this.immediateValue_;
+ const index = this.value;
if (!ticks || ticks.length == 0 || index >= ticks.length ||
!Number.isInteger(index) || !this.snaps) {
this.setAttribute('aria-valuetext', index);
@@ -408,24 +409,21 @@ cr_slider.SliderTick;
this.label_ = Number.isFinite(tick) ? '' : tick.label;
// Update label location after it has been rendered.
- this.async(() => {
+ setTimeout(() => {
const label = this.$.label;
const parentWidth = label.parentElement.offsetWidth;
const labelWidth = label.offsetWidth;
// The left and right margin are 16px.
const margin = 16;
- const knobLocation = parentWidth * this.getRatio_() + margin;
+ const knobLocation = parentWidth * this.getRatio() + margin;
const offsetStart = knobLocation - (labelWidth / 2);
- // The label should be centered over the knob. Clamping the offset to a
- // min and max value prevents the label from being cutoff.
- const max = parentWidth + 2 * margin - labelWidth;
- label.style.marginInlineStart =
- `${Math.round(clamp(0, max, offsetStart))}px`;
+ label.style.marginInlineStart = `${Math.round(offsetStart)}px`;
});
const ariaValues = [tick, ticks[0], ticks[ticks.length - 1]].map(t => {
- if (Number.isFinite(t))
+ if (Number.isFinite(t)) {
return t;
+ }
return Number.isFinite(t.ariaValue) ? t.ariaValue : t.value;
});
this.setAttribute(
@@ -437,16 +435,40 @@ cr_slider.SliderTick;
},
/**
+ * @param {number} value
+ * @return {boolean}
+ * @private
+ */
+ updateValue_: function(value) {
+ if (this.snaps) {
+ // Skip update if |value| has not passed the next value .8 units away.
+ // The value will update as the drag approaches the next value.
+ if (Math.abs(this.value - value) < .8) {
+ return false;
+ }
+ value = Math.round(value);
+ }
+ value = clamp(this.min, this.max, value);
+ if (this.value == value) {
+ return false;
+ }
+ this.value = value;
+ return true;
+ },
+
+ /**
* @param {number} clientX
* @private
*/
updateValueFromClientX_: function(clientX) {
const rect = this.$.barContainer.getBoundingClientRect();
let ratio = (clientX - rect.left) / rect.width;
- if (this.isRtl_)
+ if (this.isRtl_) {
ratio = 1 - ratio;
- this.immediateValue_ = ratio * (this.max - this.min) + this.min;
- this.ensureValidValue_();
+ }
+ if (this.updateValue_(ratio * (this.max - this.min) + this.min)) {
+ this.fire('cr-slider-value-changed');
+ }
},
_createRipple: function() {
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 722567559d7..b183a76b4eb 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
@@ -1,13 +1,27 @@
<link rel="import" href="../../html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="../shared_vars_css.html">
<dom-module id="cr-toast">
<template>
<style>
:host {
+ --cr-toast-background: #323232;
+ --cr-toast-button-color: var(--google-blue-300);
+ --cr-toast-text-color: #fff;
+ }
+
+ :host-context([dark]) {
+ --cr-toast-background: var(--google-grey-900)
+ linear-gradient(rgba(255, 255, 255, .06), rgba(255, 255, 255, .06));
+ --cr-toast-button-color: var(--google-blue-refresh-300);
+ --cr-toast-text-color: var(--google-grey-200);
+ }
+
+ :host {
align-items: center;
- background-color: #323232;
+ background: var(--cr-toast-background);
border-radius: 4px;
bottom: 0;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.28);
@@ -32,10 +46,16 @@
visibility: visible;
}
+ /* Note: this doesn't work on slotted text nodes. Something like
+ * <cr-toast>hey!</cr-toast> wont get the right text color. */
+ :host ::slotted(*) {
+ color: var(--cr-toast-text-color);
+ }
+
:host ::slotted(paper-button) {
background-color: transparent !important;
border: none !important;
- color: var(--google-blue-300) !important;
+ color: var(--cr-toast-button-color) !important;
margin-inline-start: 32px !important;
min-width: 52px !important;
padding: 8px !important;
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js
index a2bd8d7d24c..8458a76fee8 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js
@@ -70,8 +70,9 @@ Polymer({
shouldResetAutoHide = false;
}
- if (shouldResetAutoHide)
+ if (shouldResetAutoHide) {
this.resetAutoHide_();
+ }
},
/**
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html b/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
index 551ff31701c..d80478ae0c0 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
@@ -7,11 +7,28 @@
<template>
<style>
:host {
+ --cr-toggle-checked-bar-color: var(--google-blue-600);
+ --cr-toggle-checked-button-color: var(--google-blue-600);
+ --cr-toggle-checked-ink-color: var(--google-blue-600);
+ --cr-toggle-ripple-opacity: .15;
+ --cr-toggle-unchecked-bar-color: var(--google-grey-400);
+ --cr-toggle-unchecked-button-color: white;
+ --cr-toggle-unchecked-ink-color: var(--google-grey-600);
cursor: pointer;
display: block;
outline: none;
}
+ :host-context([dark]) {
+ --cr-toggle-checked-bar-color: var(--google-blue-refresh-300);
+ --cr-toggle-checked-button-color: var(--google-blue-refresh-300);
+ --cr-toggle-checked-ink-color: var(--google-blue-refresh-300);
+ --cr-toggle-ripple-opacity: .4;
+ --cr-toggle-unchecked-bar-color: var(--google-grey-refresh-500);
+ --cr-toggle-unchecked-button-color: var(--google-grey-refresh-300);
+ --cr-toggle-unchecked-ink-color: var(--google-grey-refresh-300);
+ }
+
:host([disabled]) {
cursor: initial;
opacity: var(--cr-disabled-opacity);
@@ -31,8 +48,7 @@
}
#bar {
- background-color:
- var(--cr-toggle-unchecked-bar-color, var(--google-grey-400));
+ background-color: var(--cr-toggle-unchecked-bar-color);
border-radius: 8px;
height: 12px;
left: 3px;
@@ -44,13 +60,12 @@
}
:host([checked]) #bar {
- background-color: var(
- --cr-toggle-checked-bar-color, var(--google-blue-600));
+ background-color: var(--cr-toggle-checked-bar-color);
opacity: 0.5;
}
#knob {
- background-color: var(--cr-toggle-unchecked-button-color, white);
+ background-color: var(--cr-toggle-unchecked-button-color);
border-radius: 50%;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4);
display: block;
@@ -62,8 +77,7 @@
}
:host([checked]) #knob {
- background-color: var(
- --cr-toggle-checked-button-color, var(--google-blue-600));
+ background-color: var(--cr-toggle-checked-button-color);
transform: translate3d(18px, 0, 0);
}
@@ -72,8 +86,8 @@
}
paper-ripple {
- --paper-ripple-opacity: 0.15;
- color: var(--cr-toggle-unchecked-ink-color, var(--google-grey-600));
+ --paper-ripple-opacity: var(--cr-toggle-ripple-opacity);
+ color: var(--cr-toggle-unchecked-ink-color);
height: 40px;
left: -12px;
pointer-events: none;
@@ -88,8 +102,11 @@
}
:host([checked]) paper-ripple {
+ color: var(--cr-toggle-checked-ink-color);
+ }
+
+ :host-context(html:not([dark])):host([checked]) paper-ripple {
--paper-ripple-opacity: 0.2;
- color: var(--cr-toggle-checked-ink-color, var(--google-blue-600));
}
</style>
<!-- A <button> is used (instead of a plain <div>) to avoid a corner case
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js b/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js
index df63d8a53ab..71effbbcf42 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js
@@ -73,15 +73,17 @@ Polymer({
e.preventDefault();
let diff = e.clientX - this.pointerDownX_;
- if (Math.abs(diff) < this.MOVE_THRESHOLD_PX)
+ if (Math.abs(diff) < this.MOVE_THRESHOLD_PX) {
return;
+ }
this.handledInPointerMove_ = true;
let shouldToggle = (diff * direction < 0 && this.checked) ||
(diff * direction > 0 && !this.checked);
- if (shouldToggle)
+ if (shouldToggle) {
this.toggleState_(false);
+ }
};
},
@@ -119,8 +121,9 @@ Polymer({
*/
onPointerDown_: function(e) {
// Don't do anything if this was not a primary button click or touch event.
- if (e.button != 0)
+ if (e.button != 0) {
return;
+ }
// This is necessary to have follow up pointer events fire on |this|, even
// if they occur outside of its bounds.
@@ -139,13 +142,15 @@ Polymer({
// Ignore case where 'click' handler is triggered while disabled. Can happen
// via calling the click() method.
- if (this.disabled)
+ if (this.disabled) {
return;
+ }
// User gesture has already been taken care of inside |pointermove|
// handlers, Do nothing here.
- if (this.handledInPointerMove_)
+ if (this.handledInPointerMove_) {
return;
+ }
// If no pointermove event fired, then user just clicked on the
// toggle button and therefore it should be toggled.
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
index 8fb18010132..8c3df8bff8f 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
@@ -3,6 +3,7 @@
<link rel="import" href="../cr_icons_css.html">
<link rel="import" href="../cr_toolbar/cr_toolbar_search_field.html">
<link rel="import" href="../hidden_style_css.html">
+<link rel="import" href="../shared_vars_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-media-query/iron-media-query.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
@@ -18,6 +19,11 @@
height: var(--cr-toolbar-height);
}
+ :host-context([dark]) {
+ border-bottom: var(--cr-separator-line);
+ color: var(--cr-secondary-text-color);
+ }
+
h1 {
flex: 1;
font-size: 123%;
@@ -28,6 +34,10 @@
padding-inline-end: 12px;
}
+ :host-context([dark]) :-webkit-any(h1, #menuButtonContainer) {
+ color: var(--cr-primary-text-color);
+ }
+
#leftContent {
/* margin-start here must match margin-end on #rightContent. */
margin-inline-start: 12px;
@@ -135,7 +145,7 @@
<!-- Note: showing #menuPromo relies on this dom-if being [restamp]. -->
<template is="dom-if" if="[[showMenu]]" restamp>
<paper-icon-button-light id="menuButtonContainer"
- class="icon-menu-white no-overlap">
+ class="icon-toolbar-menu no-overlap">
<button id="menuButton"
on-tap="onMenuTap_"
title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]"
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
index 0f03fdf8a69..5c86c8c1c2e 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
@@ -154,7 +154,7 @@
spellcheck="false">
</div>
<template is="dom-if" if="[[hasSearchText]]">
- <paper-icon-button-light class="icon-cancel-toolbar">
+ <paper-icon-button-light class="icon-toolbar-cancel">
<button id="clearSearch" title="[[clearLabel]]" on-tap="clearSearch_">
</button>
</paper-icon-button-light>
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 7d8e04fc56a..0c785aaa9f8 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
@@ -95,8 +95,9 @@ Polymer({
*/
computeIsSpinnerShown_: function() {
const showSpinner = this.spinnerActive && this.showingSearch;
- if (showSpinner)
+ if (showSpinner) {
this.$.spinnerTemplate.if = true;
+ }
return showSpinner;
},
@@ -108,14 +109,16 @@ Polymer({
/** @private */
onInputBlur_: function() {
this.searchFocused_ = false;
- if (!this.hasSearchText)
+ if (!this.hasSearchText) {
this.showingSearch = false;
+ }
},
/** @private */
onSearchTermKeydown_: function(e) {
- if (e.key == 'Escape')
+ if (e.key == 'Escape') {
this.showingSearch = false;
+ }
},
/**
@@ -123,8 +126,9 @@ Polymer({
* @private
*/
showSearch_: function(e) {
- if (e.target != this.$.clearSearch)
+ if (e.target != this.$.clearSearch) {
this.showingSearch = true;
+ }
},
/**
@@ -143,8 +147,9 @@ Polymer({
*/
showingSearchChanged_: function(current, previous) {
// Prevent unnecessary 'search-changed' event from firing on startup.
- if (previous == undefined)
+ if (previous == undefined) {
return;
+ }
if (this.showingSearch) {
this.focus_();
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html
index 53dfb4a7fc9..217cc5ac639 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html
@@ -3,6 +3,7 @@
<link rel="import" href="../cr_icons_css.html">
<link rel="import" href="../icons.html">
<link rel="import" href="../paper_button_style_css.html">
+<link rel="import" href="../shared_vars_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
@@ -27,6 +28,14 @@
visibility: hidden;
}
+ :host-context([dark]) {
+ background: var(--google-grey-900);
+ background-image: linear-gradient(rgba(255, 255, 255, .04),
+ rgba(255, 255, 255, .04));
+ border-bottom-color: var(--google-grey-refresh-700);
+ color: var(--cr-secondary-text-color);
+ }
+
:host([show]) {
opacity: 1;
pointer-events: initial;
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js
index 295b3e0e17e..f0cfb40b135 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js
@@ -69,7 +69,8 @@ Polymer({
/** @private */
onShowChanged_: function() {
- if (this.show)
+ if (this.show) {
this.hasShown_ = true;
+ }
},
});
diff --git a/chromium/ui/webui/resources/cr_elements/icons.html b/chromium/ui/webui/resources/cr_elements/icons.html
index 437eb4ea3a6..08b92be5bf2 100644
--- a/chromium/ui/webui/resources/cr_elements/icons.html
+++ b/chromium/ui/webui/resources/cr_elements/icons.html
@@ -42,6 +42,7 @@ blurry at 20 px). Please use 20 px icons when available.
<g id="clear"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g>
<g id="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g>
<g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></g>
+ <g id="domain"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"></path></g>
<g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g>
<g id="error-outline"><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g>
<g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></path></g>
@@ -52,6 +53,10 @@ blurry at 20 px). Please use 20 px icons when available.
<g id="fullscreen"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></g>
<g id="group"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"></path></g>
<g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"></path></g>
+ <g id="info-outline"><path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"></path></g>
+ <g id="insert-drive-file"><path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"></path></g>
+ <g id="location-on"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"></path></g>
+ <g id="mic"><path d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"></path></g>
<g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g>
<g id="open-in-new"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path></g>
<g id="person"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path></g>
@@ -70,6 +75,7 @@ blurry at 20 px). Please use 20 px icons when available.
<g id="star"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path></g>
<g id="supervisor-account" viewBox="0 0 48 48"><path d="M0 0h48v48H0z" fill="none"></path><path d="M33 24c2.76 0 4.98-2.24 4.98-5s-2.22-5-4.98-5c-2.76 0-5 2.24-5 5s2.24 5 5 5zm-15-2c3.31 0 5.98-2.69 5.98-6s-2.67-6-5.98-6c-3.31 0-6 2.69-6 6s2.69 6 6 6zm15 6c-3.67 0-11 1.84-11 5.5V38h22v-4.5c0-3.66-7.33-5.5-11-5.5zm-15-2c-4.67 0-14 2.34-14 7v5h14v-4.5c0-1.7.67-4.67 4.74-6.94C21 26.19 19.31 26 18 26z"></path></g>
<g id="sync"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"></path></g>
+ <g id="videocam"><path d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z"></path></g>
<g id="warning"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path></g>
</defs>
</svg>
diff --git a/chromium/ui/webui/resources/cr_elements/paper_button_style_css.html b/chromium/ui/webui/resources/cr_elements/paper_button_style_css.html
index 4d768d2f085..608cf8a16cb 100644
--- a/chromium/ui/webui/resources/cr_elements/paper_button_style_css.html
+++ b/chromium/ui/webui/resources/cr_elements/paper_button_style_css.html
@@ -1,5 +1,6 @@
<link rel="import" href="../html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
<link rel="import" href="shared_vars_css.html">
<!-- Common paper-button styling for Material Design WebUI. -->
@@ -7,18 +8,76 @@
<template>
<style>
paper-button {
- /* Gray color to be used when disabled, either as a background or as a
- text color depending on the type of button. */
- --disabled-color: rgb(241, 243, 244);
+ --active-shadow-rgb: var(--google-grey-800-rgb);
+ --active-shadow-action-rgb: var(--google-blue-500-rgb);
+
+ --border-color: var(--google-grey-refresh-300);
+
+ --disabled-color: var(--google-grey-refresh-100);
+ --disabled-text-color: var(--google-grey-600);
+
+ --flat-bg-action: var(--google-blue-600);
+ --flat-disabled-bg: white;
+ --flat-disabled-border-color: var(--google-grey-refresh-100);
+ --flat-focus-shadow-color: rgba(var(--google-blue-600-rgb), .4);
+ --flat-ink-color-action: white;
+ --flat-ripple-opacity-action: .32;
+ --flat-text-color-action: white;
+
+ --hover-bg-action: rgba(var(--google-blue-600-rgb), .9);
+ --hover-bg-color: rgba(var(--google-blue-500-rgb), .04);
+ --hover-border-color: var(--google-blue-refresh-100);
+ --hover-shadow-action-rgb: var(--google-blue-500-rgb);
+
/* Blue-ish color used either as a background or as a text color,
- depending on the type of button. */
+ * depending on the type of button. */
--paper-button-ink-color: var(--google-blue-600);
- --paper-ripple-opacity: 0.1;
- --text-or-bg-color: var(--google-blue-600);
- border: 1px solid rgb(218, 220, 224);
+ --ripple-opacity: .1;
+
+ --text-color: var(--google-blue-600);
+ }
+
+ [dark] paper-button,
+ :host-context([dark]) paper-button {
+ /* Only in dark. */
+ --active-bg: black linear-gradient(rgba(255, 255, 255, .06),
+ rgba(255, 255, 255, .06));
+ --active-shadow-rgb: 0, 0, 0;
+ --active-shadow-action-rgb: var(--google-blue-refresh-500-rgb);
+
+ --border-color: var(--google-grey-refresh-700);
+
+ --disabled-color: var(--google-grey-800);
+ /* --disabled-text-color is same as light mode (GG 600). */
+
+ --flat-bg-action: var(--google-blue-refresh-300);
+ /* TODO(dbeam): get --flat-disabled-bg from Namrata. */
+ --flat-disabled-bg: transparent;
+ --flat-disabled-border-color: var(--google-grey-800);
+ --flat-focus-shadow-color: rgba(var(--google-blue-refresh-300-rgb), .5);
+ --flat-ink-color-action: black;
+ --flat-ripple-opacity-action: .16;
+ --flat-text-color-action: var(--google-grey-900);
+
+ --hover-bg-action: var(--flat-bg-action)
+ linear-gradient(rgba(0, 0, 0, .08), rgba(0, 0, 0, .08));
+ --hover-bg-color: rgba(var(--google-blue-refresh-300-rgb), .08);
+ /* No change in secondary box-shadow or border color on hover
+ * (--hover-border-color, --hover-shadow-action-rgb) in dark mode. */
+
+ --paper-button-ink-color: var(--google-blue-refresh-300);
+
+ --ripple-opacity: .16;
+
+ --text-color: var(--google-blue-refresh-300);
+ }
+
+ paper-button {
+ --paper-ripple-opacity: var(--ripple-opacity);
+ border: 1px solid var(--border-color);
border-radius: 4px;
- color: var(--text-or-bg-color);
+ color: var(--text-color);
flex-shrink: 0;
font-weight: 500;
height: 32px;
@@ -29,64 +88,67 @@
}
/* Override paper-button's default transition. |animated| is automatically
- added to all paper-button instances, unfortunately. */
+ * added to all paper-button instances, unfortunately. */
paper-button[animated] {
transition: none;
}
paper-button:not([raised]).keyboard-focus,
paper-button:not([raised]).action-button.keyboard-focus {
- /* Google Blue 900 with 40% opacity. */
- box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.4);
+ box-shadow: 0 0 0 2px var(--flat-focus-shadow-color);
/* Override default paper-button's internal font-weight style. */
font-weight: 500;
}
paper-button:not(.action-button):hover {
- background-color: rgba(66, 133, 244, 0.04);
- border-color: rgb(210, 227, 252);
+ background-color: var(--hover-bg-color);
+ }
+
+ :host-context(html:not([dark])) paper-button:not(.action-button):hover {
+ border-color: var(--hover-border-color);
}
paper-button:not(.action-button):active {
- /* google-grey-800 with opacity */
+ background: var(--active-bg);
box-shadow:
- 0 1px 2px 0 rgba(60, 64, 67, 0.30),
- 0 3px 6px 2px rgba(60, 64, 67, 0.15);
+ 0 1px 2px 0 rgba(var(--active-shadow-rgb), .3),
+ 0 3px 6px 2px rgba(var(--active-shadow-rgb), .15);
+ }
+
+ paper-button:not([raised]).action-button:hover {
+ background: var(--hover-bg-action);
}
- paper-button.action-button:hover {
- /* google-blue-600 with opacity. */
- background-color: rgba(26, 115, 232, 0.9);
+ :host-context(html:not([dark])) paper-button.action-button:hover {
box-shadow:
- 0 1px 2px 0 var(--google-blue-500-opacity-30),
- 0 1px 3px 1px var(--google-blue-500-opacity-15);
+ 0 1px 2px 0 rgba(var(--hover-shadow-action-rgb), .3),
+ 0 1px 3px 1px rgba(var(--hover-shadow-action-rgb), .15);
}
paper-button.action-button:active {
box-shadow:
- 0 1px 2px 0 var(--google-blue-500-opacity-30),
- 0 3px 6px 2px var(--google-blue-500-opacity-15);
+ 0 1px 2px 0 rgba(var(--active-shadow-action-rgb), .3),
+ 0 3px 6px 2px rgba(var(--active-shadow-action-rgb), .15);
}
paper-button:not([raised]).action-button {
- --paper-ripple-opacity: 0.32;
- --paper-button-ink-color: white;
- --google-blue-500-opacity-30: rgba(66, 133, 244, 0.3);
- --google-blue-500-opacity-15: rgba(66, 133, 244, 0.15);
- background-color: var(--text-or-bg-color);
+ --paper-button-ink-color: var(--flat-ink-color-action);
+ --paper-ripple-opacity: var(--flat-ripple-opacity-action);
+ background-color: var(--flat-bg-action);
border: none;
- color: white;
+ color: var(--flat-text-color-action);
}
paper-button:not([raised])[disabled] {
- background-color: white;
- border-color: var(--disabled-color);
- color: rgb(128, 134, 139);
+ background-color: var(--flat-disabled-bg);
+ border-color: var(--flat-disabled-border-color);
+ color: var(--disabled-text-color);
}
- paper-button.action-button[disabled] {
+ paper-button:not([raised]).action-button[disabled] {
background-color: var(--disabled-color);
border-color: transparent;
+ color: var(--disabled-text-color);
}
/* cancel-button is meant to be used within a cr-dialog */
diff --git a/chromium/ui/webui/resources/cr_elements/paper_tabs_style_css.html b/chromium/ui/webui/resources/cr_elements/paper_tabs_style_css.html
index ca193b60370..c769c86a92c 100644
--- a/chromium/ui/webui/resources/cr_elements/paper_tabs_style_css.html
+++ b/chromium/ui/webui/resources/cr_elements/paper_tabs_style_css.html
@@ -11,6 +11,11 @@
--paper-tabs-selection-bar-color: var(--google-blue-600);
}
+ :host-context([dark]) paper-tabs {
+ /* TODO(dbeam): verify these colors with Namrata. */
+ --paper-tabs-selection-bar-color: var(--google-blue-refresh-300);
+ }
+
paper-tab {
--paper-tab-content: {
color: var(--google-blue-600);
@@ -19,6 +24,12 @@
color: var(--cr-secondary-text-color);
};
}
+
+ :host-context([dark]) paper-tab {
+ --paper-tab-content: {
+ color: var(--google-blue-refresh-300);
+ };
+ }
</style>
</template>
</dom-module>
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 7e4e460d6c9..bddc345379f 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
@@ -113,8 +113,9 @@ const CrPolicyIndicatorBehavior = {
* @return {string} The tooltip text for |type|.
*/
getIndicatorTooltip: function(type, name, opt_matches) {
- if (!CrPolicyStrings)
- return ''; // Tooltips may not be defined, e.g. in OOBE.
+ if (!CrPolicyStrings) {
+ return '';
+ } // Tooltips may not be defined, e.g. in OOBE.
switch (type) {
case CrPolicyIndicatorType.EXTENSION:
return name.length > 0 ?
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 e1a2bad50fe..dd564c74d94 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
@@ -16,12 +16,14 @@ const CrPolicyNetworkBehavior = {
isNetworkPolicyControlled: function(property) {
// If the property is not a dictionary, or does not have an Effective
// sub-property set, then the property is not policy controlled.
- if (typeof property != 'object' || !property.Effective)
+ if (typeof property != 'object' || !property.Effective) {
return false;
+ }
// Enforced
const effective = property.Effective;
- if (effective == 'UserPolicy' || effective == 'DevicePolicy')
+ if (effective == 'UserPolicy' || effective == 'DevicePolicy') {
return true;
+ }
// Recommended
if (typeof property.UserPolicy != 'undefined' ||
typeof property.DevicePolicy != 'undefined') {
@@ -57,17 +59,20 @@ const CrPolicyNetworkBehavior = {
*/
isEditable: function(property) {
// If the property is not a dictionary, then the property is not editable.
- if (typeof property != 'object')
+ if (typeof property != 'object') {
return false;
+ }
// If the property has a UserEditable sub-property, that determines whether
// or not it is editable.
- if (typeof property.UserEditable != 'undefined')
+ if (typeof property.UserEditable != 'undefined') {
return property.UserEditable;
+ }
// Otherwise if the property has a DeviceEditable sub-property, check that.
- if (typeof property.DeviceEditable != 'undefined')
+ if (typeof property.DeviceEditable != 'undefined') {
return property.DeviceEditable;
+ }
// If no 'Editable' sub-property exists, the policy value is not editable.
return false;
@@ -108,10 +113,96 @@ const CrPolicyNetworkBehavior = {
* @private
*/
getIndicatorTypeForSource: function(source) {
- if (source == CrOnc.Source.DEVICE_POLICY)
+ if (source == CrOnc.Source.DEVICE_POLICY) {
return CrPolicyIndicatorType.DEVICE_POLICY;
- if (source == CrOnc.Source.USER_POLICY)
+ }
+ if (source == CrOnc.Source.USER_POLICY) {
return CrPolicyIndicatorType.USER_POLICY;
+ }
return CrPolicyIndicatorType.NONE;
},
+
+ /**
+ * @param {Object} dict A managed ONC dictionary.
+ * @param {string} path A path to a setting inside |dict|.
+ * @return {!CrOnc.ManagedProperty|undefined} The value of the setting at
+ * |path|.
+ * @private
+ */
+ getSettingAtPath_: function(dict, path) {
+ const keys = path.split('.');
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ if (typeof dict !== 'object' || !(key in dict)) {
+ return undefined;
+ }
+ dict = dict[key];
+ }
+ return dict;
+ },
+
+ /**
+ * Get managed property at the given path. If the property is not policy
+ * managed, return 'undefined'. If the property's value is 'undefined' return
+ * a non-editable policy managed 'CrOnc.ManagedProperty' object.
+ * @param {!CrOnc.NetworkProperties} networkProperties
+ * @param {string} path
+ * @return {!CrOnc.ManagedProperty|undefined}
+ * @private
+ */
+ getManagedSettingAtPath_: function(networkProperties, path) {
+ if (!this.isPolicySource(networkProperties.Source)) {
+ return undefined;
+ }
+ const setting = this.getSettingAtPath_(networkProperties, path);
+ if (setting) {
+ return setting;
+ }
+ // If setting is not defined, return a non-editable managed property with
+ // 'undefined' value enforced by 'networkProperties.Source'.
+ return {
+ 'Effective': networkProperties.Source,
+ 'DeviceEditable': false,
+ 'UserEditable': false,
+ 'UserPolicy': undefined,
+ 'DevicePolicy': undefined
+ };
+ },
+
+ /**
+ * @param {!CrOnc.NetworkProperties} networkProperties
+ * @param {string} path A path to a setting inside |networkProperties|.
+ * @return {boolean} True if the setting at |path| is managed by policy (e.g.
+ * 'StaticIPConfig.NameServers').
+ */
+ isNetworkPolicyPathManaged: function(networkProperties, path) {
+ return this.isNetworkPolicyControlled(
+ this.getManagedSettingAtPath_(networkProperties, path));
+ },
+
+ /**
+ * @param {!CrOnc.NetworkProperties} networkProperties
+ * @param {string} path A path to a setting inside |networkProperties|.
+ * @return {boolean} True if the setting at |path| is enforced by policy (e.g.
+ * 'StaticIPConfig.NameServers').
+ */
+ isNetworkPolicyPathEnforced: function(networkProperties, path) {
+ return this.isNetworkPolicyEnforced(
+ this.getManagedSettingAtPath_(networkProperties, path));
+ },
+
+ /**
+ * Get policy indicator type for the setting at |path|.
+ * @param {CrOnc.NetworkProperties} networkProperties
+ * @param {string} path
+ * @return {CrPolicyIndicatorType}
+ */
+ getPolicyIndicatorType_: function(networkProperties, path) {
+ if (!this.isNetworkPolicyPathManaged(networkProperties, path)) {
+ return CrPolicyIndicatorType.NONE;
+ }
+ return networkProperties.Source == CrOnc.Source.DEVICE_POLICY ?
+ CrPolicyIndicatorType.DEVICE_POLICY :
+ CrPolicyIndicatorType.USER_POLICY;
+ },
};
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 3d139581290..0c0bb850b08 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
@@ -46,8 +46,9 @@ Polymer({
}
const effective = property.Effective;
let active = property.Active;
- if (active == undefined)
+ if (active == undefined) {
active = property[effective];
+ }
if (property.UserEditable === true &&
property.hasOwnProperty('UserPolicy')) {
@@ -78,15 +79,17 @@ Polymer({
* @private
*/
getNetworkIndicatorTooltip_: function() {
- if (this.property === undefined)
+ if (this.property === undefined) {
return '';
+ }
let matches;
if (this.indicatorType == CrPolicyIndicatorType.RECOMMENDED &&
this.property) {
let value = this.property.Active;
- if (value == undefined && this.property.Effective)
+ if (value == undefined && this.property.Effective) {
value = this.property[this.property.Effective];
+ }
matches = value == this.recommended_;
}
return this.getIndicatorTooltip(this.indicatorType, '', matches);
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 2898061a3ed..d9dfa22d232 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
@@ -46,8 +46,9 @@ Polymer({
* and |enforcement|.
*/
getIndicatorTypeForPref_: function(controlledBy, enforcement) {
- if (enforcement == chrome.settingsPrivate.Enforcement.RECOMMENDED)
+ if (enforcement == chrome.settingsPrivate.Enforcement.RECOMMENDED) {
return CrPolicyIndicatorType.RECOMMENDED;
+ }
if (enforcement == chrome.settingsPrivate.Enforcement.ENFORCED) {
switch (controlledBy) {
case chrome.settingsPrivate.ControlledBy.EXTENSION:
@@ -71,8 +72,9 @@ Polymer({
* @private
*/
getIndicatorTooltipForPref_: function(indicatorType) {
- if (!this.pref)
+ if (!this.pref) {
return '';
+ }
const matches = this.pref && this.pref.value == this.pref.recommendedValue;
return this.getIndicatorTooltip(
diff --git a/chromium/ui/webui/resources/cr_elements/shared_vars_css.html b/chromium/ui/webui/resources/cr_elements/shared_vars_css.html
index f774f420268..26d7aaf98aa 100644
--- a/chromium/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/chromium/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -6,19 +6,110 @@
<custom-style>
<style is="custom-style">
html {
+ --google-blue-50-rgb: 232, 240, 254; /* #e8f0fe */
+ --google-blue-50: rgb(var(--google-blue-50-rgb));
+ --google-blue-600-rgb: 26, 115, 232;
+ --google-blue-600: rgb(var(--google-blue-600-rgb));
+ --google-blue-900-rgb: 13, 71, 161;
+
+ --google-grey-200-rgb: 232, 234, 237; /* #e8eaed */
+ --google-grey-200: rgb(var(--google-grey-200-rgb));
+ --google-grey-400-rgb: 189, 193, 198; /* #bdc1c6 */
+ --google-grey-400: rgb(var(--google-grey-400-rgb));
+ --google-grey-600-rgb: 128, 134, 139;
+ --google-grey-600: rgb(var(--google-grey-600-rgb));
+ --google-grey-800-rgb: 60, 64, 67;
+ --google-grey-800: rgb(var(--google-grey-800-rgb));
+ --google-grey-900-rgb: 32, 33, 36; /* #202124 */
+ --google-grey-900: rgb(var(--google-grey-900-rgb));
+
+ --google-red-600-rgb: 217, 48, 37; /* #d93025 */
+ --google-red-600: rgb(var(--google-red-600-rgb));
+
+ /* -refresh differentiate from polymer's color.html. */
+ --google-blue-refresh-100-rgb: 210, 227, 252; /* #d2e3fc */
+ --google-blue-refresh-100: rgb(var(--google-blue-refresh-100-rgb));
+ --google-blue-refresh-300-rgb: 138, 180, 248; /* #8ab4f8 */
+ --google-blue-refresh-300: rgb(var(--google-blue-refresh-300-rgb));
+ --google-blue-refresh-500-rgb: 66, 133, 244; /* #4285f4 */
+ --google-blue-refresh-500: rgb(var(--google-blue-refresh-500-rgb));
+
+ --google-green-refresh-700-rgb: 24, 128, 56; /* #188038 */
+ --google-green-refresh-700: rgb(var(--google-green-refresh-700-rgb));
+
+ --google-grey-refresh-100-rgb: 241, 243, 244; /* #f1f3f4 */
+ --google-grey-refresh-100: rgb(var(--google-grey-refresh-100-rgb));
+ --google-grey-refresh-300-rgb: 218, 220, 224; /* #dadce0 */
+ --google-grey-refresh-300: rgb(var(--google-grey-refresh-300-rgb));
+ --google-grey-refresh-500-rgb: 154, 160, 166; /* #9aa0a6 */
+ --google-grey-refresh-500: rgb(var(--google-grey-refresh-500-rgb));
+ --google-grey-refresh-700-rgb: 95, 99, 104; /* #5f6368 */
+ --google-grey-refresh-700: rgb(var(--google-grey-refresh-700-rgb));
+
+ --google-red-refresh-300-rgb: 242, 139, 130; /* #f28b82 */
+ --google-red-refresh-300: rgb(var(--google-red-refresh-300-rgb));
+
--cr-primary-text-color: var(--google-grey-900);
--cr-secondary-text-color: var(--google-grey-refresh-700);
+ --cr-card-background-color: white;
+ --cr-card-elevation: {
+ box-shadow: rgba(var(--google-grey-800-rgb), .3) 0 1px 2px 0,
+ rgba(var(--google-grey-800-rgb), .15) 0 1px 3px 1px;
+ }
+
+ --cr-focused-item-color: var(--google-grey-300);
+ --cr-form-field-label-color: var(--google-grey-refresh-700);
+ --cr-link-color: var(--google-blue-700);
+ --cr-menu-background-color: white;
+ --cr-menu-background-focus-color: var(--google-grey-200);
+ --cr-menu-shadow: 0 2px 6px var(--paper-grey-500);
+ --cr-section-text-color: var(--google-grey-refresh-700);
+ --cr-separator-color: rgba(0, 0, 0, .06);
+ --cr-title-text-color: rgb(90, 90, 90);
+ --cr-toggle-color: var(--google-blue-500);
+ }
+
+ html[dark] {
+ --cr-primary-text-color: var(--google-grey-200);
+ --cr-secondary-text-color: var(--google-grey-refresh-500);
+
+ --cr-card-background-color: var(--google-grey-900);
+ --cr-card-elevation: {
+ background-image: linear-gradient(rgba(255, 255, 255, .04),
+ rgba(255, 255, 255, .04));
+ box-shadow: rgba(0, 0, 0, .3) 0 1px 2px 0,
+ rgba(0, 0, 0, .15) 0 4px 8px 3px;
+ }
+
+ /* TODO(dbeam): form-field-label, {section,title}-text, & toggle colors. */
+
+ --cr-form-field-label-color: var(--dark-secondary-color);
+ --cr-link-color: var(--google-blue-refresh-300);
+ --cr-menu-background-color: var(--google-grey-900);
+ --cr-menu-background-focus-color: rgba(var(--google-grey-800-rgb), .6);
+ --cr-menu-background-sheen: rgba(255, 255, 255, .06); /* Only dark mode. */
+ --cr-menu-shadow: rgba(0, 0, 0, .3) 0 1px 2px 0,
+ rgba(0, 0, 0, .15) 0 3px 6px 2px;
+ --cr-separator-color: rgba(255, 255, 255, .1);
+ --cr-title-text-color: var(--cr-primary-text-color);
+ }
+
+ /* Don't use color values past this point. Instead, create a variable that's
+ * set for both light and dark modes and use a single variable below. */
+
+ html {
--cr-actionable: {
cursor: pointer;
- };
+ }
--cr-button-edge-spacing: 12px;
/* Spacing between policy (controlledBy) indicator and control. */
--cr-controlled-by-spacing: 24px;
- --cr-focused-item-color: var(--google-grey-300);
+ /* Default max-width for input fields */
+ --cr-default-input-max-width: 264px;
/* The inner icon is 20px in size. The button has 8px * 2 padding. */
--cr-icon-ripple-size: 36px;
@@ -41,7 +132,7 @@
line-height: 154%; /* Apply 20px default line-height to all text. */
overflow: hidden; /* Prevent double scroll bar bugs. */
user-select: text;
- };
+ }
--cr-paper-icon-button-margin: {
/* Shift button so ripple overlaps the end of the row. */
@@ -67,6 +158,7 @@
--cr-section-three-line-min-height: 84px;
--cr-section-padding: 20px;
+ --cr-section-vertical-padding: 12px;
--cr-section-indent-width: 40px;
--cr-section-indent-padding: calc(
var(--cr-section-padding) + var(--cr-section-indent-width));
@@ -77,27 +169,25 @@
display: flex;
min-height: var(--cr-section-min-height);
padding: 0 var(--cr-section-padding);
- };
+ }
--cr-text-elide: {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- };
+ }
--cr-title-text: {
- color: rgb(90, 90, 90);
+ color: var(--cr-title-text-color);
font-size: 107.6923%; /* Go to 14px from 13px. */
font-weight: 500;
- };
+ }
--cr-section-text: {
- color: var(--google-grey-refresh-700);
+ color: var(--cr-section-text-color);
font-size: 100%; /* Likely to be 13px. */
font-weight: 500;
- };
-
- --cr-toggle-color: var(--google-blue-500);
+ }
--cr-tooltip: {
font-size: 92.31%; /* Effectively 12px if the host default is 13px. */
@@ -112,12 +202,13 @@
outline: none;
}
--cr-separator-height: 1px;
- --cr-separator-line: var(--cr-separator-height) solid rgba(0, 0, 0, 0.06);
+ --cr-separator-line: var(--cr-separator-height) solid
+ var(--cr-separator-color);
--cr-toolbar-overlay-animation-duration: 150ms;
--cr-container-shadow: {
- box-shadow: inset 0 5px 6px -3px rgba(0, 0, 0, 0.4);
+ box-shadow: inset 0 5px 6px -3px rgba(0, 0, 0, .4);
height: 6px;
left: 0;
margin-bottom: -6px;
@@ -134,40 +225,20 @@
/** MD Refresh Styles */
--cr-card-border-radius: 4px;
- --cr-card-elevation: {
- /* google-grey-800 with opacity */
- box-shadow: rgba(60, 64, 67, .3) 0 1px 2px 0,
- rgba(60, 64, 67, .15) 0 1px 3px 1px;
- }
- --cr-disabled-opacity: 0.38;
+ --cr-disabled-opacity: .38;
--cr-form-field-bottom-spacing: 16px;
- --cr-form-field-label-font-size: 0.625rem;
- --cr-form-field-label-height: 0.625rem;
- --cr-form-field-label-line-height: 0.625rem;
+ --cr-form-field-label-font-size: .625rem;
+ --cr-form-field-label-height: 1em;
+ --cr-form-field-label-line-height: 1em;
--cr-form-field-label: {
- color: var(--google-grey-refresh-700);
+ color: var(--cr-form-field-label-color);
display: block;
font-size: var(--cr-form-field-label-font-size);
font-weight: 500;
- letter-spacing: 0.4px;
+ letter-spacing: .4px;
line-height: var(--cr-form-field-label-line-height);
margin-bottom: 8px;
}
- --google-blue-50: #E8F0FE;
- --google-blue-600: #1A73E8;
- /* -refresh differentiates from google-green-700 in polymer's color.html. */
- --google-green-refresh-700: #188038;
- --google-blue-600-opacity-24: rgba(26, 115, 232, 0.24);
- /* -refresh differentiates from google-grey-100 in polymer's color.html. */
- --google-grey-refresh-100: #F1F3F4;
- --google-grey-200: #E8EAED;
- --google-grey-400: #BDC1C6;
- --google-grey-600: #80868B;
- --google-grey-600-opacity-24: rgba(128, 134, 139, 0.24);
- /* -refresh differentiates from google-grey-700 in polymer's color.html. */
- --google-grey-refresh-700: #5F6368;
- --google-grey-900: #202124;
- --google-red-600: #D93025;
}
</style>
</custom-style>
diff --git a/chromium/ui/webui/resources/cr_elements_images.grdp b/chromium/ui/webui/resources/cr_elements_images.grdp
index fbf3a9ff73c..6ac69e4cd37 100644
--- a/chromium/ui/webui/resources/cr_elements_images.grdp
+++ b/chromium/ui/webui/resources/cr_elements_images.grdp
@@ -7,40 +7,42 @@
file="images/arrow_down.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ARROW_RIGHT"
file="images/arrow_right.svg" type="BINDATA" compress="gzip" />
+ <include name="IDR_WEBUI_IMAGES_DARK_ARROW_DOWN"
+ file="images/dark/arrow_down.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_OPEN_IN_NEW"
file="images/open_in_new.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_ARROW_BACK"
file="images/icon_arrow_back.svg" type="BINDATA" compress="gzip" />
+ <include name="IDR_WEBUI_IMAGES_ICON_ARROW_DROPDOWN"
+ file="images/icon_arrow_dropdown.svg" type="BINDATA"
+ compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_CANCEL"
file="images/icon_cancel.svg" type="BINDATA" compress="gzip" />
- <include name="IDR_WEBUI_IMAGES_ICON_CANCEL_TOOLBAR"
- file="images/icon_cancel_toolbar.svg" type="BINDATA"
- compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_CLEAR"
file="images/icon_clear.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_DELETE_GRAY"
file="images/icon_delete_gray.svg" type="BINDATA" compress="gzip" />
- <include name="IDR_WEBUI_IMAGES_ICON_DELETE_WHITE"
- file="images/icon_delete_white.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_EXPAND_LESS"
file="images/icon_expand_less.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_EXPAND_MORE"
file="images/icon_expand_more.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_EXTERNAL"
file="images/open_in_new.svg" type="BINDATA" compress="gzip" />
- <include name="IDR_WEBUI_IMAGES_ICON_MENU_WHITE"
- file="images/icon_menu_white.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_MORE_VERT"
file="images/icon_more_vert.svg" type="BINDATA" compress="gzip" />
+ <include name="IDR_WEBUI_IMAGES_ICON_PICTURE_DELETE"
+ file="images/icon_picture_delete.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_REFRESH"
file="images/icon_refresh.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_SETTINGS"
file="images/icon_settings.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_SEARCH"
file="images/icon_search.svg" type="BINDATA" compress="gzip" />
- <include name="IDR_WEBUI_IMAGES_ICON_ARROW_DROPDOWN"
- file="images/icon_arrow_dropdown.svg" type="BINDATA"
+ <include name="IDR_WEBUI_IMAGES_ICON_TOOLBAR_CANCEL"
+ file="images/icon_toolbar_cancel.svg" type="BINDATA"
compress="gzip" />
+ <include name="IDR_WEBUI_IMAGES_ICON_TOOLBAR_MENU"
+ file="images/icon_toolbar_menu.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY"
file="images/icon_visibility.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY_OFF"
diff --git a/chromium/ui/webui/resources/cr_elements_resources.grdp b/chromium/ui/webui/resources/cr_elements_resources.grdp
index a5ee1112548..5b2191a81a7 100644
--- a/chromium/ui/webui/resources/cr_elements_resources.grdp
+++ b/chromium/ui/webui/resources/cr_elements_resources.grdp
@@ -126,14 +126,16 @@
file="cr_elements/cr_slider/cr_slider.js"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_CR_ELEMENTS_CR_SEARCHABLE_DROP_DOWN_HTML"
- file="cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_CR_ELEMENTS_CR_SEARCHABLE_DROP_DOWN_JS"
- file="cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js"
- type="chrome_html"
- compress="gzip" />
+ <if expr="chromeos">
+ <structure name="IDR_CR_ELEMENTS_CR_SEARCHABLE_DROP_DOWN_HTML"
+ file="cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_CR_ELEMENTS_CR_SEARCHABLE_DROP_DOWN_JS"
+ file="cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js"
+ type="chrome_html"
+ compress="gzip" />
+ </if>
<structure name="IDR_CR_ELEMENTS_CR_VIEW_MANAGER_HTML"
file="cr_elements/cr_view_manager/cr_view_manager.html"
type="chrome_html" />
@@ -333,6 +335,14 @@
file="cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js"
type="chrome_html"
compress="gzip" />
+ <structure name="IDR_CR_ELEMENTS_CR_SEARCH_FIELD_HTML"
+ file="cr_elements/cr_search_field/cr_search_field.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_CR_ELEMENTS_CR_SEARCH_FIELD_JS"
+ file="cr_elements/cr_search_field/cr_search_field.js"
+ type="chrome_html"
+ compress="gzip" />
<structure name="IDR_CR_ELEMENTS_CR_SEARCH_FIELD_BEHAVIOR_HTML"
file="cr_elements/cr_search_field/cr_search_field_behavior.html"
type="chrome_html"
diff --git a/chromium/ui/webui/resources/cr_polymer_resources.grdp b/chromium/ui/webui/resources/cr_polymer_resources.grdp
index 72c2ee250f7..a3a9519ac05 100644
--- a/chromium/ui/webui/resources/cr_polymer_resources.grdp
+++ b/chromium/ui/webui/resources/cr_polymer_resources.grdp
@@ -9,6 +9,9 @@
<structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_WITHOUT_INK"
file="html/cr/ui/focus_without_ink.html" type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_HTML_FIND_SHORTCUT_BEHAVIOR"
+ file="html/find_shortcut_behavior.html" type="chrome_html"
+ compress="gzip" />
<structure name="IDR_WEBUI_HTML_I18N_BEHAVIOR"
file="html/i18n_behavior.html" type="chrome_html"
compress="gzip" />
@@ -38,6 +41,9 @@
<structure name="IDR_WEBUI_JS_CR_UI_FOCUS_WITHOUT_INK"
file="js/cr/ui/focus_without_ink.js" type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_JS_FIND_SHORTCUT_BEHAVIOR"
+ file="js/find_shortcut_behavior.js" type="chrome_html"
+ compress="gzip" />
<structure name="IDR_WEBUI_JS_LIST_PROPERTY_UPDATE_BEHAVIOR"
file="js/list_property_update_behavior.js" type="chrome_html"
compress="gzip" />
diff --git a/chromium/ui/webui/resources/css/i18n_process.css b/chromium/ui/webui/resources/css/i18n_process.css
index 60d66f72f01..ce9ce6fe243 100644
--- a/chromium/ui/webui/resources/css/i18n_process.css
+++ b/chromium/ui/webui/resources/css/i18n_process.css
@@ -3,9 +3,7 @@
* found in the LICENSE file. */
[i18n-content]::before,
-[i18n-values*='.innerHTML:']::before,
-* /deep/ [i18n-content]::before,
-* /deep/ [i18n-values*='.innerHTML:']::before {
+[i18n-values*='.innerHTML:']::before {
/* Insert a non-breaking space into nodes that have i18n content. */
content: '\00a0';
}
@@ -13,11 +11,7 @@
[i18n-processed][i18n-content]::before,
[i18n-processed] [i18n-content]::before,
[i18n-processed][i18n-values*='.innerHTML:']::before,
-[i18n-processed] [i18n-values*='.innerHTML:']::before,
-* /deep/ [i18n-processed][i18n-content]::before,
-* /deep/ [i18n-processed] [i18n-content]::before,
-* /deep/ [i18n-processed][i18n-values*='.innerHTML:']::before,
-* /deep/ [i18n-processed] [i18n-values*='.innerHTML:']::before {
+[i18n-processed] [i18n-values*='.innerHTML:']::before {
/* Undo the non-breaking space hack after i18n processing has run. */
content: normal;
}
diff --git a/chromium/ui/webui/resources/css/md_colors.css b/chromium/ui/webui/resources/css/md_colors.css
index 7c6a46c7e41..4166c642241 100644
--- a/chromium/ui/webui/resources/css/md_colors.css
+++ b/chromium/ui/webui/resources/css/md_colors.css
@@ -11,3 +11,14 @@
*/
--md-toolbar-color: rgb(51, 103, 214);
}
+
+html[dark],
+:host-context(html[dark]) {
+ --md-background-color: rgb(32, 33, 36); /* --google-grey-900 */
+ --md-loading-message-color: #9AA0A6; /* --google-grey-refresh-500 */
+ --md-toolbar-border-color: rgb(95, 99, 104); /* --google-grey-refresh-700 */
+ /* Dark mode doesn't currently have a different toolbar background color.
+ * Instead, it uses a 1px grey border at the bottom. We set it just in case
+ * opaqueness is required for some reason. */
+ --md-toolbar-color: var(--md-background-color);
+}
diff --git a/chromium/ui/webui/resources/css/text_defaults.css b/chromium/ui/webui/resources/css/text_defaults.css
index ac989687c0f..33942fba407 100644
--- a/chromium/ui/webui/resources/css/text_defaults.css
+++ b/chromium/ui/webui/resources/css/text_defaults.css
@@ -16,6 +16,7 @@
* Otherwise its placeholders won't be expanded. */
html {
+ /* TODO(dbeam): remove this soon. Prefer dir= in HTML. */
direction: $i18n{textDirection};
}
diff --git a/chromium/ui/webui/resources/css/text_defaults_md.css b/chromium/ui/webui/resources/css/text_defaults_md.css
index 56892a04d09..a862419be6d 100644
--- a/chromium/ui/webui/resources/css/text_defaults_md.css
+++ b/chromium/ui/webui/resources/css/text_defaults_md.css
@@ -18,6 +18,7 @@
@import url(chrome://resources/css/roboto.css);
html {
+ /* TODO(dbeam): remove this soon. Prefer dir= in HTML. */
direction: $i18n{textDirection};
}
diff --git a/chromium/ui/webui/resources/html/action_link_css.html b/chromium/ui/webui/resources/html/action_link_css.html
index dc4a561c025..43984c1934d 100644
--- a/chromium/ui/webui/resources/html/action_link_css.html
+++ b/chromium/ui/webui/resources/html/action_link_css.html
@@ -15,11 +15,11 @@
[is='action-link']:active,
[is='action-link']:hover,
[is='action-link']:visited {
- color: var(--google-blue-700);
+ color: var(--cr-link-color);
}
[is='action-link'][disabled] {
- color: var(--paper-grey-600);
+ color: var(--paper-grey-600); /* TODO(dbeam): update for dark mode. */
cursor: default;
opacity: 0.65;
pointer-events: none;
diff --git a/chromium/ui/webui/resources/html/cr/ui/focus_row_behavior.html b/chromium/ui/webui/resources/html/cr/ui/focus_row_behavior.html
new file mode 100644
index 00000000000..3b50f73f822
--- /dev/null
+++ b/chromium/ui/webui/resources/html/cr/ui/focus_row_behavior.html
@@ -0,0 +1,2 @@
+<link rel="import" href="focus_row.html">
+<script src="../../../js/cr/ui/focus_row_behavior.js"></script>
diff --git a/chromium/ui/webui/resources/html/cr/ui/store.html b/chromium/ui/webui/resources/html/cr/ui/store.html
new file mode 100644
index 00000000000..4dee48a5f03
--- /dev/null
+++ b/chromium/ui/webui/resources/html/cr/ui/store.html
@@ -0,0 +1 @@
+<script src="../../../js/cr/ui/store.js"></script>
diff --git a/chromium/ui/webui/resources/html/cr/ui/store_client.html b/chromium/ui/webui/resources/html/cr/ui/store_client.html
new file mode 100644
index 00000000000..335974df9fa
--- /dev/null
+++ b/chromium/ui/webui/resources/html/cr/ui/store_client.html
@@ -0,0 +1 @@
+<script src="../../../js/cr/ui/store_client.js"></script>
diff --git a/chromium/ui/webui/resources/html/dark_mode.html b/chromium/ui/webui/resources/html/dark_mode.html
new file mode 100644
index 00000000000..b652ff82a4a
--- /dev/null
+++ b/chromium/ui/webui/resources/html/dark_mode.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="chrome://resources/js/dark_mode.js"></script>
diff --git a/chromium/ui/webui/resources/html/find_shortcut_behavior.html b/chromium/ui/webui/resources/html/find_shortcut_behavior.html
new file mode 100644
index 00000000000..9344dfb0a81
--- /dev/null
+++ b/chromium/ui/webui/resources/html/find_shortcut_behavior.html
@@ -0,0 +1,4 @@
+<link rel="import" href="../html/assert.html">
+<link rel="import" href="../html/cr.html">
+<link rel="import" href="../html/cr/ui/command.html">
+<script src="../js/find_shortcut_behavior.js"></script>
diff --git a/chromium/ui/webui/resources/html/i18n_behavior.html b/chromium/ui/webui/resources/html/i18n_behavior.html
index f7c18edc0ac..4e4b82ceaaf 100644
--- a/chromium/ui/webui/resources/html/i18n_behavior.html
+++ b/chromium/ui/webui/resources/html/i18n_behavior.html
@@ -1,2 +1,2 @@
-<link rel="import" href="../html/parse_html_subset.html">
+<link rel="import" href="parse_html_subset.html">
<script src="../js/i18n_behavior.js"></script>
diff --git a/chromium/ui/webui/resources/html/icon.html b/chromium/ui/webui/resources/html/icon.html
index eefa2f10062..4168c65d885 100644
--- a/chromium/ui/webui/resources/html/icon.html
+++ b/chromium/ui/webui/resources/html/icon.html
@@ -1,3 +1,3 @@
-<link rel="import" href="../html/cr.html">
-<link rel="import" href="../html/util.html">
+<link rel="import" href="cr.html">
+<link rel="import" href="util.html">
<script src="../js/icon.js"></script>
diff --git a/chromium/ui/webui/resources/html/load_time_data.html b/chromium/ui/webui/resources/html/load_time_data.html
index 94e11c89f18..b3f7c5f39be 100644
--- a/chromium/ui/webui/resources/html/load_time_data.html
+++ b/chromium/ui/webui/resources/html/load_time_data.html
@@ -1,3 +1,3 @@
-<script src="../js/assert.js"></script>
+<link rel="import" href="assert.html">
+<link rel="import" href="parse_html_subset.html">
<script src="../js/load_time_data.js"></script>
-<script src="../js/parse_html_subset.js"></script>
diff --git a/chromium/ui/webui/resources/html/md_select_css.html b/chromium/ui/webui/resources/html/md_select_css.html
index 115e31bbeab..9c72fee0798 100644
--- a/chromium/ui/webui/resources/html/md_select_css.html
+++ b/chromium/ui/webui/resources/html/md_select_css.html
@@ -1,4 +1,4 @@
-<link rel="import" href="../html/polymer.html">
+<link rel="import" href="polymer.html">
<link rel="import" href="../cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
@@ -6,22 +6,23 @@
<dom-module id="md-select">
<template>
<style>
- :host {
- --md-select-side-padding: 8px;
- }
-
.md-select {
--md-arrow-width: 10px;
+ --md-select-bg-color: var(--google-grey-refresh-100);
+ --md-select-focus-shadow-color: rgba(var(--google-blue-600-rgb), .4);
+ --md-select-option-bg-color: white;
+ --md-select-side-padding: 8px;
+ --md-select-text-color: var(--google-grey-900);
-webkit-appearance: none;
background: url(chrome://resources/images/arrow_down.svg)
calc(100% - var(--md-select-side-padding))
center no-repeat;
- background-color: var(--google-grey-refresh-100);
+ background-color: var(--md-select-bg-color);
background-size: var(--md-arrow-width);
border: none;
border-radius: 4px;
- color: var(--google-grey-900);
+ color: var(--md-select-text-color);
cursor: pointer;
font-family: inherit;
font-size: inherit;
@@ -37,10 +38,21 @@
width: var(--md-select-width, 200px);
}
- /* Makes sure anything within the dropdown menu has white background. */
- .md-select option,
- .md-select optgroup {
- background-color: white;
+ :host-context([dark]) .md-select {
+ --md-select-bg-color: rgba(0, 0, 0, .3);
+ --md-select-focus-shadow-color:
+ rgba(var(--google-blue-refresh-300-rgb), .5);
+ /* --google-grey-900 + 4% white. This is typically implemented with
+ * background-{color,image} for e.g. menus, but it's not currently
+ * possible to style background-image on <option>. */
+ --md-select-option-bg-color: #28292c;
+ --md-select-text-color: var(--cr-primary-text-color);
+ background-image: url(chrome://resources/images/dark/arrow_down.svg);
+ }
+
+ /* Makes sure anything within the dropdown menu has a background. */
+ .md-select :-webkit-any(option, optgroup) {
+ background-color: var(--md-select-option-bg-color);
}
.md-select[disabled] {
@@ -49,8 +61,7 @@
}
.md-select:focus {
- /* Google Blue 900 with 40% opacity. */
- box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.4);
+ box-shadow: 0 0 0 2px var(--md-select-focus-shadow-color);
}
/* Should not have an outline if opened by mouse click. */
diff --git a/chromium/ui/webui/resources/html/promise_resolver.html b/chromium/ui/webui/resources/html/promise_resolver.html
index 9dff07098f8..11f7be9febf 100644
--- a/chromium/ui/webui/resources/html/promise_resolver.html
+++ b/chromium/ui/webui/resources/html/promise_resolver.html
@@ -1,2 +1,2 @@
-<link rel="import" href="../html/assert.html">
+<link rel="import" href="assert.html">
<script src="../js/promise_resolver.js"></script>
diff --git a/chromium/ui/webui/resources/html/util.html b/chromium/ui/webui/resources/html/util.html
index 9eaa4c9f8ef..07204d0d03b 100644
--- a/chromium/ui/webui/resources/html/util.html
+++ b/chromium/ui/webui/resources/html/util.html
@@ -1,2 +1,2 @@
-<link rel="import" href="../html/assert.html">
+<link rel="import" href="assert.html">
<script src="../js/util.js"></script>
diff --git a/chromium/ui/webui/resources/html/web_ui_listener_behavior.html b/chromium/ui/webui/resources/html/web_ui_listener_behavior.html
index 9b9f8d08a16..c3dd68ac423 100644
--- a/chromium/ui/webui/resources/html/web_ui_listener_behavior.html
+++ b/chromium/ui/webui/resources/html/web_ui_listener_behavior.html
@@ -1,2 +1,2 @@
-<link rel="import" href="../html/cr.html">
+<link rel="import" href="cr.html">
<script src="../js/web_ui_listener_behavior.js"></script>
diff --git a/chromium/ui/webui/resources/html/webui_listener_tracker.html b/chromium/ui/webui/resources/html/webui_listener_tracker.html
deleted file mode 100644
index f63f03ee785..00000000000
--- a/chromium/ui/webui/resources/html/webui_listener_tracker.html
+++ /dev/null
@@ -1 +0,0 @@
-<script src="../js/webui_listener_tracker.js"></script>
diff --git a/chromium/ui/webui/resources/images/add.svg b/chromium/ui/webui/resources/images/add.svg
new file mode 100644
index 00000000000..93490965304
--- /dev/null
+++ b/chromium/ui/webui/resources/images/add.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/arrow_down.svg b/chromium/ui/webui/resources/images/dark/arrow_down.svg
new file mode 100644
index 00000000000..ae82ca45197
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/arrow_down.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="12px" viewBox="0 0 24 12" fill="#9aa0a6"><g><path d="M 0 0 L 24 0 L 12 12 z"/></g></svg>
diff --git a/chromium/ui/webui/resources/images/dark/arrow_right.svg b/chromium/ui/webui/resources/images/dark/arrow_right.svg
new file mode 100644
index 00000000000..5e128dec37c
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/arrow_right.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6"><path d="M10 7l5 5-5 5z"/></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_arrow_back.svg b/chromium/ui/webui/resources/images/dark/icon_arrow_back.svg
new file mode 100644
index 00000000000..ebb8171c191
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_arrow_back.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></path></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_arrow_dropdown.svg b/chromium/ui/webui/resources/images/dark/icon_arrow_dropdown.svg
new file mode 100644
index 00000000000..4f633ca2c64
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_arrow_dropdown.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M7 10l5 5 5-5z"></path></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_cancel.svg b/chromium/ui/webui/resources/images/dark/icon_cancel.svg
new file mode 100644
index 00000000000..99edf6b79b9
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_cancel.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 2 4" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" /></svg>
diff --git a/chromium/ui/webui/resources/images/dark/icon_clear.svg b/chromium/ui/webui/resources/images/dark/icon_clear.svg
new file mode 100644
index 00000000000..c45c8c03678
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_clear.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_delete_gray.svg b/chromium/ui/webui/resources/images/dark/icon_delete_gray.svg
new file mode 100644
index 00000000000..c7d1d76a8de
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_delete_gray.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></svg>
diff --git a/chromium/ui/webui/resources/images/dark/icon_expand_less.svg b/chromium/ui/webui/resources/images/dark/icon_expand_less.svg
new file mode 100644
index 00000000000..0be18356722
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_expand_less.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" fill="#9aa0a6" width="24" height="24"
+ viewbox="0 0 24 24">
+ <path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></path>
+</svg>
diff --git a/chromium/ui/webui/resources/images/dark/icon_expand_more.svg b/chromium/ui/webui/resources/images/dark/icon_expand_more.svg
new file mode 100644
index 00000000000..213245ef338
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_expand_more.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" fill="#9aa0a6" width="24" height="24"
+ viewBox="0 0 24 24">
+ <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"></path>
+</svg>
diff --git a/chromium/ui/webui/resources/images/dark/icon_more_vert.svg b/chromium/ui/webui/resources/images/dark/icon_more_vert.svg
new file mode 100644
index 00000000000..cd21f0f978d
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_more_vert.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_picture_delete.svg b/chromium/ui/webui/resources/images/dark/icon_picture_delete.svg
new file mode 100644
index 00000000000..9c80ccbb742
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_picture_delete.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#e8eaed" preserveAspectRatio="xMidYMid meet"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></svg>
diff --git a/chromium/ui/webui/resources/images/dark/icon_refresh.svg b/chromium/ui/webui/resources/images/dark/icon_refresh.svg
new file mode 100644
index 00000000000..d588c54f969
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_refresh.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_search.svg b/chromium/ui/webui/resources/images/dark/icon_search.svg
new file mode 100644
index 00000000000..8145e692fc8
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_search.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_settings.svg b/chromium/ui/webui/resources/images/dark/icon_settings.svg
new file mode 100644
index 00000000000..2b2c7b02c6b
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_settings.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"></path></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_toolbar_cancel.svg b/chromium/ui/webui/resources/images/dark/icon_toolbar_cancel.svg
new file mode 100644
index 00000000000..52d7346abb7
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_toolbar_cancel.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 2 4" fill="#e8eaed" preserveAspectRatio="xMidYMid meet"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" /></svg>
diff --git a/chromium/ui/webui/resources/images/dark/icon_toolbar_menu.svg b/chromium/ui/webui/resources/images/dark/icon_toolbar_menu.svg
new file mode 100644
index 00000000000..3af72ab8caa
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_toolbar_menu.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="#e8eaed" preserveAspectRatio="xMidYMid meet"><rect x="2" y="4" width="16" height="2"></rect><rect x="2" y="9" width="16" height="2"></rect><rect x="2" y="14" width="16" height="2"></rect></svg>
diff --git a/chromium/ui/webui/resources/images/dark/icon_visibility.svg b/chromium/ui/webui/resources/images/dark/icon_visibility.svg
new file mode 100644
index 00000000000..3be0cc8c110
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_visibility.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"></path></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/dark/icon_visibility_off.svg b/chromium/ui/webui/resources/images/dark/icon_visibility_off.svg
new file mode 100644
index 00000000000..9d52f6de608
--- /dev/null
+++ b/chromium/ui/webui/resources/images/dark/icon_visibility_off.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"/></svg>
diff --git a/chromium/ui/webui/resources/images/error_badge.svg b/chromium/ui/webui/resources/images/error_badge.svg
new file mode 100644
index 00000000000..4367b025606
--- /dev/null
+++ b/chromium/ui/webui/resources/images/error_badge.svg
@@ -0,0 +1,9 @@
+<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <path d="M10 2c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8zm.8 12H9.2v-1.6h1.6V14zm0-3.2H9.2V6h1.6v4.8z" id="a"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <circle fill="#FFF" cx="10" cy="10" r="10"/>
+ <use fill="#D93025" fill-rule="nonzero" xlink:href="#a"/>
+ </g>
+</svg>
diff --git a/chromium/ui/webui/resources/images/icon_delete_white.svg b/chromium/ui/webui/resources/images/icon_picture_delete.svg
index 24fea4e5acb..24fea4e5acb 100644
--- a/chromium/ui/webui/resources/images/icon_delete_white.svg
+++ b/chromium/ui/webui/resources/images/icon_picture_delete.svg
diff --git a/chromium/ui/webui/resources/images/icon_cancel_toolbar.svg b/chromium/ui/webui/resources/images/icon_toolbar_cancel.svg
index b497c453cd7..b497c453cd7 100644
--- a/chromium/ui/webui/resources/images/icon_cancel_toolbar.svg
+++ b/chromium/ui/webui/resources/images/icon_toolbar_cancel.svg
diff --git a/chromium/ui/webui/resources/images/icon_menu_white.svg b/chromium/ui/webui/resources/images/icon_toolbar_menu.svg
index aab80273728..aab80273728 100644
--- a/chromium/ui/webui/resources/images/icon_menu_white.svg
+++ b/chromium/ui/webui/resources/images/icon_toolbar_menu.svg
diff --git a/chromium/ui/webui/resources/js/BUILD.gn b/chromium/ui/webui/resources/js/BUILD.gn
index 3c1eb17bc2a..cd593b4f5ef 100644
--- a/chromium/ui/webui/resources/js/BUILD.gn
+++ b/chromium/ui/webui/resources/js/BUILD.gn
@@ -17,7 +17,9 @@ js_type_check("js_resources") {
":action_link",
":assert",
":cr",
+ ":dark_mode",
":event_tracker",
+ ":find_shortcut_behavior",
":i18n_behavior",
":i18n_template",
":i18n_template_no_process",
@@ -29,7 +31,6 @@ js_type_check("js_resources") {
":search_highlight_utils",
":util",
":web_ui_listener_behavior",
- ":webui_listener_tracker",
":webui_resource_test",
]
}
@@ -48,13 +49,15 @@ js_library("cr") {
externs_list = [ "$externs_path/chrome_send.js" ]
}
-js_library("event_tracker") {
-}
-
-js_library("webui_listener_tracker") {
+js_library("dark_mode") {
deps = [
":cr",
+ ":load_time_data",
]
+ externs_list = [ "$externs_path/pending.js" ]
+}
+
+js_library("event_tracker") {
}
js_library("search_highlight_utils") {
@@ -124,3 +127,11 @@ js_library("web_ui_listener_behavior") {
js_library("webui_resource_test") {
externs_list = [ "dom_automation_controller.js" ]
}
+
+js_library("find_shortcut_behavior") {
+ deps = [
+ ":assert",
+ ":cr",
+ "cr/ui:command",
+ ]
+}
diff --git a/chromium/ui/webui/resources/js/action_link.js b/chromium/ui/webui/resources/js/action_link.js
index 99dc0fdf3df..8a4006313c7 100644
--- a/chromium/ui/webui/resources/js/action_link.js
+++ b/chromium/ui/webui/resources/js/action_link.js
@@ -32,8 +32,9 @@ class ActionLink extends HTMLAnchorElement {
// Action links can start disabled (e.g. <a is="action-link" disabled>).
this.tabIndex = this.disabled ? -1 : 0;
- if (!this.hasAttribute('role'))
+ if (!this.hasAttribute('role')) {
this.setAttribute('role', 'link');
+ }
this.addEventListener('keydown', function(e) {
if (!this.disabled && e.key == 'Enter' && !this.href) {
@@ -63,8 +64,9 @@ class ActionLink extends HTMLAnchorElement {
document.addEventListener('mouseup', removePreventDefault);
// If focus started via mouse press, don't show an outline.
- if (document.activeElement != this)
+ if (document.activeElement != this) {
this.classList.add('no-outline');
+ }
});
this.addEventListener('blur', function() {
@@ -74,10 +76,11 @@ class ActionLink extends HTMLAnchorElement {
/** @param {boolean} disabled */
set disabled(disabled) {
- if (disabled)
+ if (disabled) {
HTMLAnchorElement.prototype.setAttribute.call(this, 'disabled', '');
- else
+ } else {
HTMLAnchorElement.prototype.removeAttribute.call(this, 'disabled');
+ }
this.tabIndex = disabled ? -1 : 0;
}
@@ -87,18 +90,20 @@ class ActionLink extends HTMLAnchorElement {
/** @override */
setAttribute(attr, val) {
- if (attr.toLowerCase() == 'disabled')
+ if (attr.toLowerCase() == 'disabled') {
this.disabled = true;
- else
+ } else {
HTMLAnchorElement.prototype.setAttribute.apply(this, arguments);
+ }
}
/** @override */
removeAttribute(attr) {
- if (attr.toLowerCase() == 'disabled')
+ if (attr.toLowerCase() == 'disabled') {
this.disabled = false;
- else
+ } else {
HTMLAnchorElement.prototype.removeAttribute.apply(this, arguments);
+ }
}
}
customElements.define('action-link', ActionLink, {extends: 'a'});
diff --git a/chromium/ui/webui/resources/js/assert.js b/chromium/ui/webui/resources/js/assert.js
index e46a056778e..7686b7c941b 100644
--- a/chromium/ui/webui/resources/js/assert.js
+++ b/chromium/ui/webui/resources/js/assert.js
@@ -17,17 +17,19 @@
*/
function assert(condition, opt_message) {
if (!condition) {
- var message = 'Assertion failed';
- if (opt_message)
+ let message = 'Assertion failed';
+ if (opt_message) {
message = message + ': ' + opt_message;
- var error = new Error(message);
- var global = function() {
+ }
+ const error = new Error(message);
+ const global = function() {
/** @type {boolean} */
this.traceAssertionsForTesting;
return this;
}();
- if (global.traceAssertionsForTesting)
+ if (global.traceAssertionsForTesting) {
console.warn(error.stack);
+ }
throw error;
}
return condition;
diff --git a/chromium/ui/webui/resources/js/cr.js b/chromium/ui/webui/resources/js/cr.js
index 75a4e86e2ee..5c157d45cbb 100644
--- a/chromium/ui/webui/resources/js/cr.js
+++ b/chromium/ui/webui/resources/js/cr.js
@@ -2,18 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * The global object.
- * @type {!Object}
- * @const
- */
-var global = this;
-
/** @typedef {{eventName: string, uid: number}} */
+// eslint-disable-next-line no-var
var WebUIListener;
/** Platform, package, object property, and Event support. **/
-var cr = cr || function() {
+// eslint-disable-next-line no-var
+var cr = cr || function(global) {
'use strict';
/**
@@ -30,10 +25,10 @@ var cr = cr || function() {
* @private
*/
function exportPath(name, opt_object, opt_objectToExportTo) {
- var parts = name.split('.');
- var cur = opt_objectToExportTo || global;
+ const parts = name.split('.');
+ let cur = opt_objectToExportTo || global;
- for (var part; parts.length && (part = parts.shift());) {
+ for (let part; parts.length && (part = parts.shift());) {
if (!parts.length && opt_object !== undefined) {
// last part and we have an object; use it
cur[part] = opt_object;
@@ -54,7 +49,7 @@ var cr = cr || function() {
* @param {*} oldValue The old value for the property.
*/
function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
- var e = new Event(propertyName + 'Change');
+ const e = new Event(propertyName + 'Change');
e.propertyName = propertyName;
e.newValue = newValue;
e.oldValue = oldValue;
@@ -76,7 +71,7 @@ var cr = cr || function() {
* @enum {string}
* @const
*/
- var PropertyKind = {
+ const PropertyKind = {
/**
* Plain old JS property where the backing data is stored as a "private"
* field on the object.
@@ -106,19 +101,20 @@ var cr = cr || function() {
* @return {function():*} The getter for the property.
*/
function getGetter(name, kind) {
+ let attributeName;
switch (kind) {
case PropertyKind.JS:
- var privateName = name + '_';
+ const privateName = name + '_';
return function() {
return this[privateName];
};
case PropertyKind.ATTR:
- var attributeName = getAttributeName(name);
+ attributeName = getAttributeName(name);
return function() {
return this.getAttribute(attributeName);
};
case PropertyKind.BOOL_ATTR:
- var attributeName = getAttributeName(name);
+ attributeName = getAttributeName(name);
return function() {
return this.hasAttribute(attributeName);
};
@@ -141,45 +137,51 @@ var cr = cr || function() {
* @return {function(*):void} The function to use as a setter.
*/
function getSetter(name, kind, opt_setHook) {
+ let attributeName;
switch (kind) {
case PropertyKind.JS:
- var privateName = name + '_';
+ const privateName = name + '_';
return function(value) {
- var oldValue = this[name];
+ const oldValue = this[name];
if (value !== oldValue) {
this[privateName] = value;
- if (opt_setHook)
+ if (opt_setHook) {
opt_setHook.call(this, value, oldValue);
+ }
dispatchPropertyChange(this, name, value, oldValue);
}
};
case PropertyKind.ATTR:
- var attributeName = getAttributeName(name);
+ attributeName = getAttributeName(name);
return function(value) {
- var oldValue = this[name];
+ const oldValue = this[name];
if (value !== oldValue) {
- if (value == undefined)
+ if (value == undefined) {
this.removeAttribute(attributeName);
- else
+ } else {
this.setAttribute(attributeName, value);
- if (opt_setHook)
+ }
+ if (opt_setHook) {
opt_setHook.call(this, value, oldValue);
+ }
dispatchPropertyChange(this, name, value, oldValue);
}
};
case PropertyKind.BOOL_ATTR:
- var attributeName = getAttributeName(name);
+ attributeName = getAttributeName(name);
return function(value) {
- var oldValue = this[name];
+ const oldValue = this[name];
if (value !== oldValue) {
- if (value)
+ if (value) {
this.setAttribute(attributeName, name);
- else
+ } else {
this.removeAttribute(attributeName);
- if (opt_setHook)
+ }
+ if (opt_setHook) {
opt_setHook.call(this, value, oldValue);
+ }
dispatchPropertyChange(this, name, value, oldValue);
}
};
@@ -200,22 +202,25 @@ var cr = cr || function() {
* property is set, but before the propertyChange event is fired.
*/
function defineProperty(obj, name, opt_kind, opt_setHook) {
- if (typeof obj == 'function')
+ if (typeof obj == 'function') {
obj = obj.prototype;
+ }
- var kind = /** @type {PropertyKind} */ (opt_kind || PropertyKind.JS);
+ const kind = /** @type {PropertyKind} */ (opt_kind || PropertyKind.JS);
- if (!obj.__lookupGetter__(name))
+ if (!obj.__lookupGetter__(name)) {
obj.__defineGetter__(name, getGetter(name, kind));
+ }
- if (!obj.__lookupSetter__(name))
+ if (!obj.__lookupSetter__(name)) {
obj.__defineSetter__(name, getSetter(name, kind, opt_setHook));
+ }
}
/**
* Counter for use with createUid
*/
- var uidCounter = 1;
+ let uidCounter = 1;
/**
* @return {number} A new unique ID.
@@ -231,8 +236,9 @@ var cr = cr || function() {
* @return {number} The unique ID for the item.
*/
function getUid(item) {
- if (item.hasOwnProperty('uid'))
+ if (item.hasOwnProperty('uid')) {
return item.uid;
+ }
return item.uid = createUid();
}
@@ -247,7 +253,7 @@ var cr = cr || function() {
* during the dispatch this will return false.
*/
function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
- var e = new Event(type, {
+ const e = new Event(type, {
bubbles: opt_bubbles,
cancelable: opt_cancelable === undefined || opt_cancelable
});
@@ -274,16 +280,17 @@ var cr = cr || function() {
* the names and values of the new fields.
*/
function define(name, fun) {
- var obj = exportPath(name);
- var exports = fun();
- for (var propertyName in exports) {
+ const obj = exportPath(name);
+ const exports = fun();
+ for (const propertyName in exports) {
// Maybe we should check the prototype chain here? The current usage
// pattern is always using an object literal so we only care about own
// properties.
- var propertyDescriptor =
+ const propertyDescriptor =
Object.getOwnPropertyDescriptor(exports, propertyName);
- if (propertyDescriptor)
+ if (propertyDescriptor) {
Object.defineProperty(obj, propertyName, propertyDescriptor);
+ }
}
}
@@ -310,7 +317,7 @@ var cr = cr || function() {
function makePublic(ctor, methods, opt_target) {
methods.forEach(function(method) {
ctor[method] = function() {
- var target = opt_target ?
+ const target = opt_target ?
// Disable document.getElementById restriction since cr.js should
// not depend on util.js.
// eslint-disable-next-line no-restricted-properties
@@ -328,7 +335,7 @@ var cr = cr || function() {
* sendWithPromise and is unique across all invocations of said method.
* @type {!Object<!PromiseResolver>}
*/
- var chromeSendResolverMap = {};
+ const chromeSendResolverMap = {};
/**
* The named method the WebUI handler calls directly in response to a
@@ -344,13 +351,14 @@ var cr = cr || function() {
* @param {*} response The response as sent from C++.
*/
function webUIResponse(id, isSuccess, response) {
- var resolver = chromeSendResolverMap[id];
+ const resolver = chromeSendResolverMap[id];
delete chromeSendResolverMap[id];
- if (isSuccess)
+ if (isSuccess) {
resolver.resolve(response);
- else
+ } else {
resolver.reject(response);
+ }
}
/**
@@ -362,9 +370,9 @@ var cr = cr || function() {
* @return {!Promise}
*/
function sendWithPromise(methodName, var_args) {
- var args = Array.prototype.slice.call(arguments, 1);
- var promiseResolver = new PromiseResolver();
- var id = methodName + '_' + createUid();
+ const args = Array.prototype.slice.call(arguments, 1);
+ const promiseResolver = new PromiseResolver();
+ const id = methodName + '_' + createUid();
chromeSendResolverMap[id] = promiseResolver;
chrome.send(methodName, [id].concat(args));
return promiseResolver.promise;
@@ -377,7 +385,7 @@ var cr = cr || function() {
* the same event.
* @type {!Object<!Object<!Function>>}
*/
- var webUIListenerMap = {};
+ const webUIListenerMap = {};
/**
* The named method the WebUI handler calls directly when an event occurs.
@@ -388,15 +396,15 @@ var cr = cr || function() {
* @param {...*} var_args Additional arguments passed from C++.
*/
function webUIListenerCallback(event, var_args) {
- var eventListenersMap = webUIListenerMap[event];
+ const eventListenersMap = webUIListenerMap[event];
if (!eventListenersMap) {
// C++ event sent for an event that has no listeners.
// TODO(dpapad): Should a warning be displayed here?
return;
}
- var args = Array.prototype.slice.call(arguments, 1);
- for (var listenerId in eventListenersMap) {
+ const args = Array.prototype.slice.call(arguments, 1);
+ for (const listenerId in eventListenersMap) {
eventListenersMap[listenerId].apply(null, args);
}
}
@@ -411,7 +419,7 @@ var cr = cr || function() {
*/
function addWebUIListener(eventName, callback) {
webUIListenerMap[eventName] = webUIListenerMap[eventName] || {};
- var uid = createUid();
+ const uid = createUid();
webUIListenerMap[eventName][uid] = callback;
return {eventName: eventName, uid: uid};
}
@@ -424,7 +432,7 @@ var cr = cr || function() {
* removed.
*/
function removeWebUIListener(listener) {
- var listenerExists = webUIListenerMap[listener.eventName] &&
+ const listenerExists = webUIListenerMap[listener.eventName] &&
webUIListenerMap[listener.eventName][listener.uid];
if (listenerExists) {
delete webUIListenerMap[listener.eventName][listener.uid];
@@ -486,4 +494,4 @@ var cr = cr || function() {
return /iPad|iPhone|iPod/.test(navigator.platform);
}
};
-}();
+}(this);
diff --git a/chromium/ui/webui/resources/js/cr/event_target.js b/chromium/ui/webui/resources/js/cr/event_target.js
index 24cdf294124..94c955f77c0 100644
--- a/chromium/ui/webui/resources/js/cr/event_target.js
+++ b/chromium/ui/webui/resources/js/cr/event_target.js
@@ -10,6 +10,7 @@
/**
* @typedef {EventListener|function(!Event):*}
*/
+// eslint-disable-next-line no-var
var EventListenerType;
cr.define('cr', function() {
@@ -30,14 +31,16 @@ cr.define('cr', function() {
* called when the event is dispatched.
*/
addEventListener: function(type, handler) {
- if (!this.listeners_)
+ if (!this.listeners_) {
this.listeners_ = Object.create(null);
+ }
if (!(type in this.listeners_)) {
this.listeners_[type] = [handler];
} else {
- var handlers = this.listeners_[type];
- if (handlers.indexOf(handler) < 0)
+ const handlers = this.listeners_[type];
+ if (handlers.indexOf(handler) < 0) {
handlers.push(handler);
+ }
}
},
@@ -47,17 +50,19 @@ cr.define('cr', function() {
* @param {EventListenerType} handler The handler for the event.
*/
removeEventListener: function(type, handler) {
- if (!this.listeners_)
+ if (!this.listeners_) {
return;
+ }
if (type in this.listeners_) {
- var handlers = this.listeners_[type];
- var index = handlers.indexOf(handler);
+ const handlers = this.listeners_[type];
+ const index = handlers.indexOf(handler);
if (index >= 0) {
// Clean up if this was the last listener.
- if (handlers.length == 1)
+ if (handlers.length == 1) {
delete this.listeners_[type];
- else
+ } else {
handlers.splice(index, 1);
+ }
}
}
},
@@ -70,26 +75,28 @@ cr.define('cr', function() {
* calls preventDefault on the event object then this returns false.
*/
dispatchEvent: function(event) {
- if (!this.listeners_)
+ if (!this.listeners_) {
return true;
+ }
// Since we are using DOM Event objects we need to override some of the
// properties and methods so that we can emulate this correctly.
- var self = this;
+ const self = this;
event.__defineGetter__('target', function() {
return self;
});
- var type = event.type;
- var prevented = 0;
+ const type = event.type;
+ let prevented = 0;
if (type in this.listeners_) {
// Clone to prevent removal during dispatch
- var handlers = this.listeners_[type].concat();
- for (var i = 0, handler; handler = handlers[i]; i++) {
- if (handler.handleEvent)
+ const handlers = this.listeners_[type].concat();
+ for (let i = 0, handler; handler = handlers[i]; i++) {
+ if (handler.handleEvent) {
prevented |= handler.handleEvent.call(handler, event) === false;
- else
+ } else {
prevented |= handler.call(this, event) === false;
+ }
}
}
diff --git a/chromium/ui/webui/resources/js/cr/link_controller.js b/chromium/ui/webui/resources/js/cr/link_controller.js
index 67515e8b9f0..d3d10760958 100644
--- a/chromium/ui/webui/resources/js/cr/link_controller.js
+++ b/chromium/ui/webui/resources/js/cr/link_controller.js
@@ -82,15 +82,15 @@ cr.define('cr', function() {
openUrlFromEvent: function(url, e) {
// We only support keydown Enter and non right click events.
if (e.type == 'keydown' && e.key == 'Enter' || e.button != 2) {
- var kind;
- var ctrl = cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey;
+ let kind;
+ const ctrl = cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey;
- if (e.button == 1 || ctrl) // middle, ctrl or keyboard
+ if (e.button == 1 || ctrl) { // middle, ctrl or keyboard
kind = e.shiftKey ? cr.LinkKind.FOREGROUND_TAB :
cr.LinkKind.BACKGROUND_TAB;
- else // left or keyboard
+ } else { // left or keyboard
kind = e.shiftKey ? cr.LinkKind.WINDOW : cr.LinkKind.SELF;
-
+ }
this.openUrls([url], kind);
}
},
@@ -111,22 +111,24 @@ cr.define('cr', function() {
* @param {cr.LinkKind} kind The kind of open we want to do.
*/
openUrls: function(urls, kind) {
- if (urls.length < 1)
+ if (urls.length < 1) {
return;
+ }
if (urls.length > this.warningLimit) {
- if (!this.window.confirm(this.getWarningMessage(urls.length)))
+ if (!this.window.confirm(this.getWarningMessage(urls.length))) {
return;
+ }
}
// Fix '#124' URLs since opening those in a new window does not work. We
// prepend the base URL when we encounter those.
- var base = this.window.location.href.split('#')[0];
+ const base = this.window.location.href.split('#')[0];
urls = urls.map(function(url) {
return url[0] == '#' ? base + url : url;
});
- var incognito = kind == cr.LinkKind.INCOGNITO;
+ const incognito = kind == cr.LinkKind.INCOGNITO;
if (kind == cr.LinkKind.WINDOW || incognito) {
chrome.windows.create({url: urls, incognito: incognito});
} else if (
diff --git a/chromium/ui/webui/resources/js/cr/ui.js b/chromium/ui/webui/resources/js/cr/ui.js
index 9c9cc21b5a2..1b36844e65f 100644
--- a/chromium/ui/webui/resources/js/cr/ui.js
+++ b/chromium/ui/webui/resources/js/cr/ui.js
@@ -13,15 +13,17 @@ cr.define('cr.ui', function() {
* needs to have a {@code decorate} function.
*/
function decorate(source, constr) {
- var elements;
- if (typeof source == 'string')
+ let elements;
+ if (typeof source == 'string') {
elements = cr.doc.querySelectorAll(source);
- else
+ } else {
elements = [source];
+ }
- for (var i = 0, el; el = elements[i]; i++) {
- if (!(el instanceof constr))
+ for (let i = 0, el; el = elements[i]; i++) {
+ if (!(el instanceof constr)) {
constr.decorate(el);
+ }
}
}
@@ -30,11 +32,12 @@ cr.define('cr.ui', function() {
*/
function createElementHelper(tagName, opt_bag) {
// Allow passing in ownerDocument to create in a different document.
- var doc;
- if (opt_bag && opt_bag.ownerDocument)
+ let doc;
+ if (opt_bag && opt_bag.ownerDocument) {
doc = opt_bag.ownerDocument;
- else
+ } else {
doc = cr.doc;
+ }
return doc.createElement(tagName);
}
@@ -61,7 +64,7 @@ cr.define('cr.ui', function() {
* {@code decorate} method added to it.
*/
function define(tagNameOrFunction) {
- var createFunction, tagName;
+ let createFunction, tagName;
if (typeof tagNameOrFunction == 'function') {
createFunction = tagNameOrFunction;
tagName = '';
@@ -79,9 +82,9 @@ cr.define('cr.ui', function() {
* @constructor
*/
function f(opt_propertyBag) {
- var el = createFunction(tagName, opt_propertyBag);
+ const el = createFunction(tagName, opt_propertyBag);
f.decorate(el);
- for (var propertyName in opt_propertyBag) {
+ for (const propertyName in opt_propertyBag) {
el[propertyName] = opt_propertyBag[propertyName];
}
return el;
@@ -112,39 +115,40 @@ cr.define('cr.ui', function() {
function limitInputWidth(el, parentEl, min, opt_scale) {
// Needs a size larger than borders
el.style.width = '10px';
- var doc = el.ownerDocument;
- var win = doc.defaultView;
- var computedStyle = win.getComputedStyle(el);
- var parentComputedStyle = win.getComputedStyle(parentEl);
- var rtl = computedStyle.direction == 'rtl';
+ const doc = el.ownerDocument;
+ const win = doc.defaultView;
+ const computedStyle = win.getComputedStyle(el);
+ const parentComputedStyle = win.getComputedStyle(parentEl);
+ const rtl = computedStyle.direction == 'rtl';
// To get the max width we get the width of the treeItem minus the position
// of the input.
- var inputRect = el.getBoundingClientRect(); // box-sizing
- var parentRect = parentEl.getBoundingClientRect();
- var startPos = rtl ? parentRect.right - inputRect.right :
- inputRect.left - parentRect.left;
+ const inputRect = el.getBoundingClientRect(); // box-sizing
+ const parentRect = parentEl.getBoundingClientRect();
+ const startPos = rtl ? parentRect.right - inputRect.right :
+ inputRect.left - parentRect.left;
// Add up border and padding of the input.
- var inner = parseInt(computedStyle.borderLeftWidth, 10) +
+ const inner = parseInt(computedStyle.borderLeftWidth, 10) +
parseInt(computedStyle.paddingLeft, 10) +
parseInt(computedStyle.paddingRight, 10) +
parseInt(computedStyle.borderRightWidth, 10);
// We also need to subtract the padding of parent to prevent it to overflow.
- var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) :
- parseInt(parentComputedStyle.paddingRight, 10);
+ const parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) :
+ parseInt(parentComputedStyle.paddingRight, 10);
- var max = parentEl.clientWidth - startPos - inner - parentPadding;
- if (opt_scale)
+ let max = parentEl.clientWidth - startPos - inner - parentPadding;
+ if (opt_scale) {
max *= opt_scale;
+ }
function limit() {
if (el.scrollWidth > max) {
el.style.width = max + 'px';
} else {
el.style.width = 0;
- var sw = el.scrollWidth;
+ const sw = el.scrollWidth;
if (sw < min) {
el.style.width = min + 'px';
} else {
@@ -164,8 +168,9 @@ cr.define('cr.ui', function() {
* @return {string} e.g. '16px'.
*/
function toCssPx(pixels) {
- if (!window.isFinite(pixels))
+ if (!window.isFinite(pixels)) {
console.error('Pixel value is not a number: ' + pixels);
+ }
return Math.round(pixels) + 'px';
}
@@ -176,8 +181,8 @@ cr.define('cr.ui', function() {
* @param {MouseEvent} e Initial click event.
*/
function swallowDoubleClick(e) {
- var doc = e.target.ownerDocument;
- var counter = Math.min(1, e.detail);
+ const doc = e.target.ownerDocument;
+ let counter = Math.min(1, e.detail);
function swallow(e) {
e.stopPropagation();
e.preventDefault();
diff --git a/chromium/ui/webui/resources/js/cr/ui/BUILD.gn b/chromium/ui/webui/resources/js/cr/ui/BUILD.gn
index 86b41a08d99..41ad3a882c1 100644
--- a/chromium/ui/webui/resources/js/cr/ui/BUILD.gn
+++ b/chromium/ui/webui/resources/js/cr/ui/BUILD.gn
@@ -4,7 +4,14 @@
import("//third_party/closure_compiler/compile_js.gni")
-js_type_check("closure_compile") {
+group("closure_compile") {
+ deps = [
+ ":ui_resources",
+ "page_manager:closure_compile",
+ ]
+}
+
+js_type_check("ui_resources") {
deps = [
":array_data_model",
":autocomplete_list",
@@ -17,6 +24,7 @@ js_type_check("closure_compile") {
":focus_manager",
":focus_outline_manager",
":focus_row",
+ ":focus_row_behavior",
":focus_without_ink",
":grid",
":list",
@@ -31,6 +39,8 @@ js_type_check("closure_compile") {
":overlay",
":position_util",
":splitter",
+ ":store",
+ ":store_client",
":table",
":tree",
]
@@ -51,6 +61,14 @@ js_library("autocomplete_list") {
]
}
+js_library("bubble") {
+ deps = [
+ "..:ui",
+ "../..:cr",
+ "../..:event_tracker",
+ ]
+}
+
js_library("command") {
deps = [
"..:ui",
@@ -109,6 +127,12 @@ js_library("focus_outline_manager") {
]
}
+js_library("focus_row_behavior") {
+ deps = [
+ ":focus_row",
+ ]
+}
+
js_library("focus_row") {
deps = [
"../..:assert",
@@ -223,6 +247,19 @@ js_library("splitter") {
]
}
+js_library("store") {
+ deps = [
+ "../..:cr",
+ ]
+}
+
+js_library("store_client") {
+ deps = [
+ ":store",
+ "../..:cr",
+ ]
+}
+
js_library("table") {
deps = [
":list",
diff --git a/chromium/ui/webui/resources/js/cr/ui/array_data_model.js b/chromium/ui/webui/resources/js/cr/ui/array_data_model.js
index d5a596e76e0..4998fc7c380 100644
--- a/chromium/ui/webui/resources/js/cr/ui/array_data_model.js
+++ b/chromium/ui/webui/resources/js/cr/ui/array_data_model.js
@@ -15,7 +15,7 @@
// <include src="../../assert.js">
cr.define('cr.ui', function() {
- /** @const */ var EventTarget = cr.EventTarget;
+ /** @const */ const EventTarget = cr.EventTarget;
/**
* A data model that wraps a simple array and supports sorting by storing
@@ -29,7 +29,7 @@ cr.define('cr.ui', function() {
this.indexes_ = [];
this.compareFunctions_ = {};
- for (var i = 0; i < array.length; i++) {
+ for (let i = 0; i < array.length; i++) {
this.indexes_.push(i);
}
}
@@ -53,8 +53,9 @@ cr.define('cr.ui', function() {
* @return {*} The element at the given index.
*/
item: function(index) {
- if (index >= 0 && index < this.length)
+ if (index >= 0 && index < this.length) {
return this.array_[this.indexes_[index]];
+ }
return undefined;
},
@@ -110,9 +111,10 @@ cr.define('cr.ui', function() {
* @return {number} The index of the first found element or -1 if not found.
*/
indexOf: function(item, opt_fromIndex) {
- for (var i = opt_fromIndex || 0; i < this.indexes_.length; i++) {
- if (item === this.item(i))
+ for (let i = opt_fromIndex || 0; i < this.indexes_.length; i++) {
+ if (item === this.item(i)) {
return i;
+ }
}
return -1;
},
@@ -124,7 +126,7 @@ cr.define('cr.ui', function() {
* @return {Array} An array of elements in the selected range.
*/
slice: function(opt_from, opt_to) {
- var arr = this.array_;
+ const arr = this.array_;
return this.indexes_.slice(opt_from, opt_to).map(function(index) {
return arr[index];
});
@@ -141,15 +143,16 @@ cr.define('cr.ui', function() {
* @return {!Array} An array with the removed items.
*/
splice: function(index, deleteCount, var_args) {
- var addCount = arguments.length - 2;
- var newIndexes = [];
- var deletePermutation = [];
- var deletedItems = [];
- var newArray = [];
+ const addCount = arguments.length - 2;
+ const newIndexes = [];
+ const deletePermutation = [];
+ const deletedItems = [];
+ const newArray = [];
index = Math.min(index, this.indexes_.length);
deleteCount = Math.min(deleteCount, this.indexes_.length - index);
// Copy items before the insertion point.
- for (var i = 0; i < index; i++) {
+ let i;
+ for (i = 0; i < index; i++) {
newIndexes.push(newArray.length);
deletePermutation.push(i);
newArray.push(this.array_[this.indexes_[i]]);
@@ -160,7 +163,7 @@ cr.define('cr.ui', function() {
deletedItems.push(this.array_[this.indexes_[i]]);
}
// Insert new items instead deleted ones.
- for (var j = 0; j < addCount; j++) {
+ for (let j = 0; j < addCount; j++) {
newIndexes.push(newArray.length);
newArray.push(arguments[j + 2]);
}
@@ -176,16 +179,16 @@ cr.define('cr.ui', function() {
this.array_ = newArray;
// TODO(arv): Maybe unify splice and change events?
- var spliceEvent = new Event('splice');
+ const spliceEvent = new Event('splice');
spliceEvent.removed = deletedItems;
spliceEvent.added = Array.prototype.slice.call(arguments, 2);
- var status = this.sortStatus;
+ const status = this.sortStatus;
// if sortStatus.field is null, this restores original order.
- var sortPermutation =
+ const sortPermutation =
this.doSort_(this.sortStatus.field, this.sortStatus.direction);
if (sortPermutation) {
- var splicePermutation = deletePermutation.map(function(element) {
+ const splicePermutation = deletePermutation.map(function(element) {
return element != -1 ? sortPermutation[element] : -1;
});
this.dispatchPermutedEvent_(splicePermutation);
@@ -201,8 +204,9 @@ cr.define('cr.ui', function() {
// change), and then sort again.
// Still need to finish the sorting above (including events), so
// list will not go to inconsistent state.
- if (status.field)
+ if (status.field) {
this.delayedSort_(status.field, status.direction);
+ }
return deletedItems;
},
@@ -216,7 +220,7 @@ cr.define('cr.ui', function() {
* @return {number} The new length of the model.
*/
push: function(var_args) {
- var args = Array.prototype.slice.call(arguments);
+ const args = Array.prototype.slice.call(arguments);
args.unshift(this.length, 0);
this.splice.apply(this, args);
return this.length;
@@ -233,9 +237,10 @@ cr.define('cr.ui', function() {
* @param {*} newItem New item.
*/
replaceItem: function(oldItem, newItem) {
- var index = this.indexOf(oldItem);
- if (index < 0)
+ const index = this.indexOf(oldItem);
+ if (index < 0) {
return;
+ }
this.array_[this.indexes_[index]] = newItem;
this.updateIndex(index);
},
@@ -263,18 +268,19 @@ cr.define('cr.ui', function() {
assert(index >= 0 && index < this.length, 'Invalid index');
}, this);
- for (var i = 0; i < indexes.length; i++) {
- var e = new Event('change');
+ for (let i = 0; i < indexes.length; i++) {
+ const e = new Event('change');
e.index = indexes[i];
this.dispatchEvent(e);
}
if (this.sortStatus.field) {
- var status = this.sortStatus;
- var sortPermutation =
+ const status = this.sortStatus;
+ const sortPermutation =
this.doSort_(this.sortStatus.field, this.sortStatus.direction);
- if (sortPermutation)
+ if (sortPermutation) {
this.dispatchPermutedEvent_(sortPermutation);
+ }
// We should first call prepareSort (data may change), and then sort.
// Still need to finish the sorting above (including events), so
// list will not go to inconsistent state.
@@ -312,7 +318,7 @@ cr.define('cr.ui', function() {
* @private
*/
delayedSort_: function(field, direction) {
- var self = this;
+ const self = this;
setTimeout(function() {
// If the sort status has been changed, sorting has already done
// on the change event.
@@ -330,12 +336,13 @@ cr.define('cr.ui', function() {
* @param {string} direction Sort direction.
*/
sort: function(field, direction) {
- var self = this;
+ const self = this;
this.prepareSort(field, function() {
- var sortPermutation = self.doSort_(field, direction);
- if (sortPermutation)
+ const sortPermutation = self.doSort_(field, direction);
+ if (sortPermutation) {
self.dispatchPermutedEvent_(sortPermutation);
+ }
self.dispatchSortEvent_();
});
},
@@ -347,36 +354,39 @@ cr.define('cr.ui', function() {
* @private
*/
doSort_: function(field, direction) {
- var compareFunction = this.sortFunction_(field, direction);
- var positions = [];
- for (var i = 0; i < this.length; i++) {
+ const compareFunction = this.sortFunction_(field, direction);
+ const positions = [];
+ for (let i = 0; i < this.length; i++) {
positions[this.indexes_[i]] = i;
}
- var sorted = this.indexes_.every(function(element, index, array) {
+ const sorted = this.indexes_.every(function(element, index, array) {
return index == 0 || compareFunction(element, array[index - 1]) >= 0;
});
- if (!sorted)
+ if (!sorted) {
this.indexes_.sort(compareFunction);
+ }
this.sortStatus_ = this.createSortStatus(field, direction);
- var sortPermutation = [];
- var changed = false;
- for (var i = 0; i < this.length; i++) {
- if (positions[this.indexes_[i]] != i)
+ const sortPermutation = [];
+ let changed = false;
+ for (let i = 0; i < this.length; i++) {
+ if (positions[this.indexes_[i]] != i) {
changed = true;
+ }
sortPermutation[positions[this.indexes_[i]]] = i;
}
- if (changed)
+ if (changed) {
return sortPermutation;
+ }
return null;
},
dispatchSortEvent_: function() {
- var e = new Event('sorted');
+ const e = new Event('sorted');
this.dispatchEvent(e);
},
dispatchPermutedEvent_: function(permutation) {
- var e = new Event('permuted');
+ const e = new Event('permuted');
e.permutation = permutation;
e.newLength = this.length;
this.dispatchEvent(e);
@@ -391,9 +401,9 @@ cr.define('cr.ui', function() {
* @private
*/
createCompareFunction_: function(field) {
- var compareFunction =
+ const compareFunction =
this.compareFunctions_ ? this.compareFunctions_[field] : null;
- var defaultValuesCompareFunction = this.defaultValuesCompareFunction;
+ const defaultValuesCompareFunction = this.defaultValuesCompareFunction;
if (compareFunction) {
return compareFunction;
} else {
@@ -410,20 +420,23 @@ cr.define('cr.ui', function() {
* @private
*/
sortFunction_: function(field, direction) {
- var compareFunction = null;
- if (field !== null)
+ let compareFunction = null;
+ if (field !== null) {
compareFunction = this.createCompareFunction_(field);
- var dirMultiplier = direction == 'desc' ? -1 : 1;
+ }
+ const dirMultiplier = direction == 'desc' ? -1 : 1;
return function(index1, index2) {
- var item1 = this.array_[index1];
- var item2 = this.array_[index2];
+ const item1 = this.array_[index1];
+ const item2 = this.array_[index2];
- var compareResult = 0;
- if (typeof(compareFunction) === 'function')
+ let compareResult = 0;
+ if (typeof (compareFunction) === 'function') {
compareResult = compareFunction.call(null, item1, item2);
- if (compareResult != 0)
+ }
+ if (compareResult != 0) {
return dirMultiplier * compareResult;
+ }
return dirMultiplier *
this.defaultValuesCompareFunction(index1, index2);
}.bind(this);
@@ -434,10 +447,12 @@ cr.define('cr.ui', function() {
*/
defaultValuesCompareFunction: function(a, b) {
// We could insert i18n comparisons here.
- if (a < b)
+ if (a < b) {
return -1;
- if (a > b)
+ }
+ if (a > b) {
return 1;
+ }
return 0;
}
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js b/chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js
index db05e102c36..3d2fd1c63fe 100644
--- a/chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js
+++ b/chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js
@@ -3,9 +3,9 @@
// found in the LICENSE file.
cr.define('cr.ui', function() {
- /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
- /** @const */ var List = cr.ui.List;
- /** @const */ var ListItem = cr.ui.ListItem;
+ /** @const */ const ArrayDataModel = cr.ui.ArrayDataModel;
+ /** @const */ const List = cr.ui.List;
+ /** @const */ const ListItem = cr.ui.ListItem;
/**
* Creates a new autocomplete list item.
@@ -16,7 +16,7 @@ cr.define('cr.ui', function() {
* @extends {cr.ui.ListItem}
*/
function AutocompleteListItem(pageInfo) {
- var el = cr.doc.createElement('div');
+ const el = cr.doc.createElement('div');
el.pageInfo_ = pageInfo;
AutocompleteListItem.decorate(el);
return el;
@@ -38,18 +38,18 @@ cr.define('cr.ui', function() {
decorate: function() {
ListItem.prototype.decorate.call(this);
- var title = this.pageInfo_['title'];
- var url = this.pageInfo_['displayURL'];
- var titleEl = this.ownerDocument.createElement('span');
+ const title = this.pageInfo_['title'];
+ const url = this.pageInfo_['displayURL'];
+ const titleEl = this.ownerDocument.createElement('span');
titleEl.className = 'title';
titleEl.textContent = title || url;
this.appendChild(titleEl);
if (title && title.length > 0 && url != title) {
- var separatorEl = this.ownerDocument.createTextNode(' - ');
+ const separatorEl = this.ownerDocument.createTextNode(' - ');
this.appendChild(separatorEl);
- var urlEl = this.ownerDocument.createElement('span');
+ const urlEl = this.ownerDocument.createElement('span');
urlEl.className = 'url';
urlEl.textContent = url;
this.appendChild(urlEl);
@@ -62,7 +62,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {cr.ui.List}
*/
- var AutocompleteList = cr.ui.define('list');
+ const AutocompleteList = cr.ui.define('list');
AutocompleteList.prototype = {
__proto__: List.prototype,
@@ -96,13 +96,14 @@ cr.define('cr.ui', function() {
this.itemConstructor = AutocompleteListItem;
this.textFieldKeyHandler_ = this.handleAutocompleteKeydown_.bind(this);
- var self = this;
+ const self = this;
this.textFieldInputHandler_ = function(e) {
self.requestSuggestions(self.targetInput_.value);
};
this.addEventListener('change', function(e) {
- if (self.selectedItem)
+ if (self.selectedItem) {
self.handleSelectedSuggestion(self.selectedItem);
+ }
});
// Start hidden; adding suggestions will unhide.
this.hidden = true;
@@ -144,9 +145,10 @@ cr.define('cr.ui', function() {
* @param {Object} selectedSuggestion
*/
handleSelectedSuggestion: function(selectedSuggestion) {
- var input = this.targetInput_;
- if (!input)
+ const input = this.targetInput_;
+ if (!input) {
return;
+ }
input.value = selectedSuggestion['url'];
// Programatically change the value won't trigger a change event, but
// clients are likely to want to know when changes happen, so fire one.
@@ -159,8 +161,9 @@ cr.define('cr.ui', function() {
* @param {HTMLElement} input The input element to attach to.
*/
attachToInput: function(input) {
- if (this.targetInput_ == input)
+ if (this.targetInput_ == input) {
return;
+ }
this.detach();
this.targetInput_ = input;
@@ -186,9 +189,10 @@ cr.define('cr.ui', function() {
* Detaches the autocomplete popup from its current input element, if any.
*/
detach: function() {
- var input = this.targetInput_;
- if (!input)
+ const input = this.targetInput_;
+ if (!input) {
return;
+ }
input.removeEventListener('keydown', this.textFieldKeyHandler_, true);
input.removeEventListener('input', this.textFieldInputHandler_);
@@ -206,7 +210,7 @@ cr.define('cr.ui', function() {
* resized.
*/
syncWidthAndPositionToInput: function() {
- var input = this.targetInput_;
+ const input = this.targetInput_;
if (input) {
this.style.width = input.getBoundingClientRect().width + 'px';
cr.ui.positionPopupAroundElement(input, this, cr.ui.AnchorType.BELOW);
@@ -235,9 +239,10 @@ cr.define('cr.ui', function() {
* @private
*/
handleAutocompleteKeydown_: function(event) {
- if (this.hidden)
+ if (this.hidden) {
return;
- var handled = false;
+ }
+ let handled = false;
switch (event.key) {
case 'Escape':
this.suggestions = [];
diff --git a/chromium/ui/webui/resources/js/cr/ui/bubble.js b/chromium/ui/webui/resources/js/cr/ui/bubble.js
index 055f1cb59b7..9b971f2dcd1 100644
--- a/chromium/ui/webui/resources/js/cr/ui/bubble.js
+++ b/chromium/ui/webui/resources/js/cr/ui/bubble.js
@@ -65,7 +65,7 @@ cr.define('cr.ui', function() {
* @extends {HTMLDivElement}
* @implements {EventListener}
*/
- var BubbleBase = cr.ui.define('div');
+ const BubbleBase = cr.ui.define('div');
/**
* The horizontal distance between the tip of the arrow and the reference edge
@@ -111,8 +111,9 @@ cr.define('cr.ui', function() {
* @param {HTMLElement} node The new anchor node.
*/
set anchorNode(node) {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
this.anchorNode_ = node;
},
@@ -123,10 +124,11 @@ cr.define('cr.ui', function() {
* @param {HTMLElement} node The root node of the new content.
*/
set content(node) {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
- var bubbleContent = this.querySelector('.bubble-content');
+ const bubbleContent = this.querySelector('.bubble-content');
bubbleContent.innerHTML = '';
bubbleContent.appendChild(node);
},
@@ -137,13 +139,15 @@ cr.define('cr.ui', function() {
* @param {cr.ui.ArrowLocation} location The new arrow location.
*/
set arrowLocation(location) {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
this.arrowAtRight_ = location == cr.ui.ArrowLocation.TOP_END ||
location == cr.ui.ArrowLocation.BOTTOM_END;
- if (document.documentElement.dir == 'rtl')
+ if (document.documentElement.dir == 'rtl') {
this.arrowAtRight_ = !this.arrowAtRight_;
+ }
this.arrowAtTop_ = location == cr.ui.ArrowLocation.TOP_START ||
location == cr.ui.ArrowLocation.TOP_END;
},
@@ -154,8 +158,9 @@ cr.define('cr.ui', function() {
* @param {cr.ui.BubbleAlignment} alignment The new bubble alignment.
*/
set bubbleAlignment(alignment) {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
this.bubbleAlignment_ = alignment;
},
@@ -166,30 +171,33 @@ cr.define('cr.ui', function() {
* hidden so that it does not point to a nonsensical location on the page.
*/
reposition: function() {
- var documentWidth = document.documentElement.clientWidth;
- var documentHeight = document.documentElement.clientHeight;
- var anchor = this.anchorNode_.getBoundingClientRect();
- var anchorMid = (anchor.left + anchor.right) / 2;
- var bubble = this.getBoundingClientRect();
- var arrow = this.querySelector('.bubble-arrow').getBoundingClientRect();
-
+ const documentWidth = document.documentElement.clientWidth;
+ const documentHeight = document.documentElement.clientHeight;
+ const anchor = this.anchorNode_.getBoundingClientRect();
+ const anchorMid = (anchor.left + anchor.right) / 2;
+ const bubble = this.getBoundingClientRect();
+ const arrow = this.querySelector('.bubble-arrow').getBoundingClientRect();
+
+ let left;
+ let top;
if (this.bubbleAlignment_ == cr.ui.BubbleAlignment.ENTIRELY_VISIBLE) {
// Work out horizontal placement. The bubble is initially positioned so
// that the arrow tip points toward the midpoint of the anchor and is
// BubbleBase.ARROW_OFFSET pixels from the reference edge and (as
// specified by the arrow location). If the bubble is not entirely
// within view, it is then shifted, preserving the arrow tip position.
- var left = this.arrowAtRight_ ?
+ left = this.arrowAtRight_ ?
anchorMid + BubbleBase.ARROW_OFFSET - bubble.width :
anchorMid - BubbleBase.ARROW_OFFSET;
- var maxLeftPos =
+ const maxLeftPos =
documentWidth - bubble.width - BubbleBase.MIN_VIEWPORT_EDGE_MARGIN;
- var minLeftPos = BubbleBase.MIN_VIEWPORT_EDGE_MARGIN;
- if (document.documentElement.dir == 'rtl')
+ const minLeftPos = BubbleBase.MIN_VIEWPORT_EDGE_MARGIN;
+ if (document.documentElement.dir == 'rtl') {
left = Math.min(Math.max(left, minLeftPos), maxLeftPos);
- else
+ } else {
left = Math.max(Math.min(left, maxLeftPos), minLeftPos);
- var arrowTip = Math.min(
+ }
+ const arrowTip = Math.min(
Math.max(
arrow.width / 2,
this.arrowAtRight_ ? left + bubble.width - anchorMid :
@@ -208,33 +216,32 @@ cr.define('cr.ui', function() {
// * Outside the anchor, arrow tip overlapping the anchor (arrow at
// bottom/top, opposite the specified arrow location).
// * Overlapping the anchor.
- var offsetTop = Math.min(
+ const offsetTop = Math.min(
documentHeight - anchor.bottom - bubble.height, arrow.height / 2);
- var offsetBottom =
+ const offsetBottom =
Math.min(anchor.top - bubble.height, arrow.height / 2);
if (offsetTop < 0 && offsetBottom < 0) {
- var top = 0;
+ top = 0;
this.updateArrowPosition_(false, false, arrowTip);
} else if (
offsetTop > offsetBottom ||
offsetTop == offsetBottom && this.arrowAtTop_) {
- var top = anchor.bottom + offsetTop;
+ top = anchor.bottom + offsetTop;
this.updateArrowPosition_(true, true, arrowTip);
} else {
- var top = anchor.top - bubble.height - offsetBottom;
+ top = anchor.top - bubble.height - offsetBottom;
this.updateArrowPosition_(true, false, arrowTip);
}
} else {
if (this.bubbleAlignment_ ==
cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE) {
- var left =
- this.arrowAtRight_ ? anchor.right - bubble.width : anchor.left;
+ left = this.arrowAtRight_ ? anchor.right - bubble.width : anchor.left;
} else {
- var left = this.arrowAtRight_ ?
+ left = this.arrowAtRight_ ?
anchorMid - this.clientWidth + BubbleBase.ARROW_OFFSET :
anchorMid - BubbleBase.ARROW_OFFSET;
}
- var top = this.arrowAtTop_ ?
+ top = this.arrowAtTop_ ?
anchor.bottom + arrow.height / 2 :
anchor.top - this.clientHeight - arrow.height / 2;
this.updateArrowPosition_(
@@ -249,14 +256,15 @@ cr.define('cr.ui', function() {
* Show the bubble.
*/
show: function() {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
this.attachToDOM_();
this.hidden = false;
this.reposition();
- var doc = assert(this.ownerDocument);
+ const doc = assert(this.ownerDocument);
this.eventTracker_ = new EventTracker;
this.eventTracker_.add(doc, 'keydown', this, true);
this.eventTracker_.add(doc, 'mousedown', this, true);
@@ -266,8 +274,9 @@ cr.define('cr.ui', function() {
* Hide the bubble.
*/
hide: function() {
- if (this.hidden)
+ if (this.hidden) {
return;
+ }
this.eventTracker_.removeAll();
this.hidden = true;
@@ -306,12 +315,13 @@ cr.define('cr.ui', function() {
* @private
*/
updateArrowPosition_: function(visible, atTop, tipOffset) {
- var bubbleArrow = this.querySelector('.bubble-arrow');
+ const bubbleArrow = this.querySelector('.bubble-arrow');
bubbleArrow.hidden = !visible;
- if (!visible)
+ if (!visible) {
return;
+ }
- var edgeOffset = (-bubbleArrow.clientHeight / 2) + 'px';
+ let edgeOffset = (-bubbleArrow.clientHeight / 2) + 'px';
bubbleArrow.style.top = atTop ? edgeOffset : 'auto';
bubbleArrow.style.bottom = atTop ? 'auto' : edgeOffset;
@@ -329,7 +339,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {cr.ui.BubbleBase}
*/
- var Bubble = cr.ui.define('div');
+ const Bubble = cr.ui.define('div');
Bubble.prototype = {
// Set up the prototype chain.
@@ -341,7 +351,7 @@ cr.define('cr.ui', function() {
decorate: function() {
BubbleBase.prototype.decorate.call(this);
- var close = document.createElement('div');
+ const close = document.createElement('div');
close.className = 'bubble-close';
this.insertBefore(close, this.querySelector('.bubble-content'));
@@ -358,8 +368,9 @@ cr.define('cr.ui', function() {
* parameters.
*/
set handleCloseEvent(handler) {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
this.handleCloseEvent_ = handler;
},
@@ -386,8 +397,9 @@ cr.define('cr.ui', function() {
* Show the bubble.
*/
show: function() {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
BubbleBase.prototype.show.call(this);
@@ -427,7 +439,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {cr.ui.BubbleBase}
*/
- var AutoCloseBubble = cr.ui.define('div');
+ const AutoCloseBubble = cr.ui.define('div');
AutoCloseBubble.prototype = {
// Set up the prototype chain.
@@ -449,8 +461,9 @@ cr.define('cr.ui', function() {
* @param {HTMLElement} node The new DOM sibling node.
*/
set domSibling(node) {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
this.domSibling_ = node;
},
@@ -459,13 +472,14 @@ cr.define('cr.ui', function() {
* Show the bubble.
*/
show: function() {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
BubbleBase.prototype.show.call(this);
this.domSibling_.showingBubble = true;
- var doc = this.ownerDocument;
+ const doc = this.ownerDocument;
this.eventTracker_.add(doc, 'click', this, true);
this.eventTracker_.add(doc, 'mousewheel', this, true);
this.eventTracker_.add(doc, 'scroll', this, true);
@@ -493,21 +507,24 @@ cr.define('cr.ui', function() {
handleEvent: function(event) {
BubbleBase.prototype.handleEvent.call(this, event);
+ let target;
switch (event.type) {
// Close the bubble when the user clicks outside it, except if it is a
// left-click on the bubble's target element (allowing the target to
// handle the event and close the bubble itself).
case 'mousedown':
case 'click':
- var target = assertInstanceof(event.target, Node);
- if (event.button == 0 && this.anchorNode_.contains(target))
+ target = assertInstanceof(event.target, Node);
+ if (event.button == 0 && this.anchorNode_.contains(target)) {
break;
+ }
// Close the bubble when the underlying document is scrolled.
case 'mousewheel':
case 'scroll':
- var target = assertInstanceof(event.target, Node);
- if (this.contains(target))
+ target = assertInstanceof(event.target, Node);
+ if (this.contains(target)) {
break;
+ }
// Close the bubble when the window is resized.
case 'resize':
this.hide();
@@ -515,9 +532,10 @@ cr.define('cr.ui', function() {
// Close the bubble when the focus moves to an element that is not the
// bubble target and is not inside the bubble.
case 'elementFocused':
- var target = assertInstanceof(event.target, Node);
- if (!this.anchorNode_.contains(target) && !this.contains(target))
+ target = assertInstanceof(event.target, Node);
+ if (!this.anchorNode_.contains(target) && !this.contains(target)) {
this.hide();
+ }
break;
}
},
@@ -529,7 +547,7 @@ cr.define('cr.ui', function() {
* @private
*/
attachToDOM_: function() {
- var parent = this.domSibling_.parentNode;
+ const parent = this.domSibling_.parentNode;
parent.insertBefore(this, this.domSibling_.nextSibling);
},
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/bubble_button.js b/chromium/ui/webui/resources/js/cr/ui/bubble_button.js
index a5901e59ab7..9b0094b20ae 100644
--- a/chromium/ui/webui/resources/js/cr/ui/bubble_button.js
+++ b/chromium/ui/webui/resources/js/cr/ui/bubble_button.js
@@ -10,7 +10,7 @@ cr.define('cr.ui', function() {
* @extends {HTMLSpanElement}
* @implements {EventListener}
*/
- var BubbleButton = cr.ui.define('span');
+ const BubbleButton = cr.ui.define('span');
BubbleButton.prototype = {
__proto__: HTMLSpanElement.prototype,
@@ -50,8 +50,9 @@ cr.define('cr.ui', function() {
switch (event.type) {
// Toggle the bubble on left click. Let any other clicks propagate.
case 'click':
- if (event.button != 0)
+ if (event.button != 0) {
return;
+ }
break;
// Toggle the bubble when <Return> or <Space> is pressed. Let any other
// key presses propagate.
@@ -67,8 +68,9 @@ cr.define('cr.ui', function() {
// Blur focus when a mouse button is pressed, matching the behavior of
// other Web UI elements.
case 'mousedown':
- if (document.activeElement)
+ if (document.activeElement) {
document.activeElement.blur();
+ }
event.preventDefault();
return;
}
diff --git a/chromium/ui/webui/resources/js/cr/ui/card_slider.js b/chromium/ui/webui/resources/js/cr/ui/card_slider.js
index dd4693db133..ac9a74dade9 100644
--- a/chromium/ui/webui/resources/js/cr/ui/card_slider.js
+++ b/chromium/ui/webui/resources/js/cr/ui/card_slider.js
@@ -118,7 +118,7 @@ cr.define('cr.ui', function() {
* events will be ignored, rather than flipping between pages.
*/
initialize: function(ignoreMouseWheelEvents) {
- var view = this.container_.ownerDocument.defaultView;
+ const view = this.container_.ownerDocument.defaultView;
assert(
view.getComputedStyle(this.container_).display == '-webkit-box',
'Container should be display -webkit-box.');
@@ -146,7 +146,7 @@ cr.define('cr.ui', function() {
// available. Note that this has minimal impact in the common case of
// no touch events (eg. we're mainly just adding listeners for events that
// will never trigger).
- var TouchHandler = cr.ui.TouchHandler;
+ const TouchHandler = cr.ui.TouchHandler;
this.container_.addEventListener(
TouchHandler.EventType.TOUCH_START, this.onTouchStart_.bind(this));
this.container_.addEventListener(
@@ -204,7 +204,7 @@ cr.define('cr.ui', function() {
* @private
*/
updateSelectedCardAttributes_: function() {
- for (var i = 0; i < this.cards_.length; i++) {
+ for (let i = 0; i < this.cards_.length; i++) {
if (i == this.currentCard_) {
this.cards_[i].classList.add('selected-card');
this.cards_[i].removeAttribute('aria-hidden');
@@ -220,8 +220,9 @@ cr.define('cr.ui', function() {
* @private
*/
updateCardWidths_: function() {
- for (var i = 0, card; card = this.cards_[i]; i++)
+ for (let i = 0, card; card = this.cards_[i]; i++) {
card.style.width = this.cardWidth_ + 'px';
+ }
},
/**
@@ -270,8 +271,9 @@ cr.define('cr.ui', function() {
* @private
*/
onMouseWheel_: function(e) {
- if (e.wheelDeltaX == 0)
+ if (e.wheelDeltaX == 0) {
return;
+ }
// Continuous devices such as an Apple Touchpad or Apple MagicMouse will
// send arbitrary delta values. Conversly, standard mousewheels will
@@ -279,22 +281,25 @@ cr.define('cr.ui', function() {
// chance we mistake a continuous device for a non-continuous device.
// Unfortunately there isn't a better way to do this until real touch
// events are available to desktop clients.)
- var DISCRETE_DELTA = 120;
- if (e.wheelDeltaX % DISCRETE_DELTA)
+ const DISCRETE_DELTA = 120;
+ if (e.wheelDeltaX % DISCRETE_DELTA) {
this.mouseWheelIsContinuous_ = true;
+ }
if (this.mouseWheelIsContinuous_) {
// For continuous devices, detect a page swipe when the accumulated
// delta matches a pre-defined threshhold. After changing the page,
// ignore wheel events for a short time before repeating this process.
- if (this.mouseWheelCardSelected_)
+ if (this.mouseWheelCardSelected_) {
return;
+ }
this.mouseWheelScrollAmount_ += e.wheelDeltaX;
if (Math.abs(this.mouseWheelScrollAmount_) >= 600) {
- var pagesToScroll = this.mouseWheelScrollAmount_ > 0 ? 1 : -1;
- if (!isRTL())
+ let pagesToScroll = this.mouseWheelScrollAmount_ > 0 ? 1 : -1;
+ if (!isRTL()) {
pagesToScroll *= -1;
- var newCardIndex = this.currentCard + pagesToScroll;
+ }
+ let newCardIndex = this.currentCard + pagesToScroll;
newCardIndex =
Math.min(this.cards_.length - 1, Math.max(0, newCardIndex));
this.selectCard(newCardIndex, true);
@@ -302,18 +307,20 @@ cr.define('cr.ui', function() {
}
} else {
// For discrete devices, consider each wheel tick a page change.
- var pagesToScroll = e.wheelDeltaX / DISCRETE_DELTA;
- if (!isRTL())
+ let pagesToScroll = e.wheelDeltaX / DISCRETE_DELTA;
+ if (!isRTL()) {
pagesToScroll *= -1;
- var newCardIndex = this.currentCard + pagesToScroll;
+ }
+ let newCardIndex = this.currentCard + pagesToScroll;
newCardIndex =
Math.min(this.cards_.length - 1, Math.max(0, newCardIndex));
this.selectCard(newCardIndex, true);
}
// We got a mouse wheel event, so cancel any pending scroll wheel timeout.
- if (this.scrollClearTimeout_ != null)
+ if (this.scrollClearTimeout_ != null) {
clearTimeout(this.scrollClearTimeout_);
+ }
// If we didn't use up all the scroll, hold onto it for a little bit, but
// drop it after a delay.
if (this.mouseWheelScrollAmount_ != 0) {
@@ -340,8 +347,9 @@ cr.define('cr.ui', function() {
*/
onTransitionEnd_: function(e) {
// Ignore irrelevant transitions that might bubble up.
- if (e.target !== this.container_ || e.propertyName != 'transform')
+ if (e.target !== this.container_ || e.propertyName != 'transform') {
return;
+ }
this.fireChangeEndedEvent_(true);
},
@@ -352,7 +360,7 @@ cr.define('cr.ui', function() {
* @private
*/
fireChangeEndedEvent_: function(wasAnimated) {
- var e = document.createEvent('Event');
+ const e = document.createEvent('Event');
e.initEvent('cardSlider:card_change_ended', true, true);
e.cardSlider = this;
e.changedTo = this.currentCard_;
@@ -376,10 +384,11 @@ cr.define('cr.ui', function() {
this.updateSelectedCardAttributes_();
- if (this.currentCard_ == -1)
+ if (this.currentCard_ == -1) {
this.currentCard_ = 0;
- else if (index <= this.currentCard_)
+ } else if (index <= this.currentCard_) {
this.selectCard(this.currentCard_ + 1, false, true, true);
+ }
this.fireAddedEvent_(card, index);
},
@@ -402,7 +411,7 @@ cr.define('cr.ui', function() {
*/
fireAddedEvent_: function(card, index) {
this.assertValidIndex_(index);
- var e = document.createEvent('Event');
+ const e = document.createEvent('Event');
e.initEvent('cardSlider:card_added', true, true);
e.addedIndex = index;
e.addedCard = card;
@@ -438,12 +447,13 @@ cr.define('cr.ui', function() {
*/
removeCardAtIndex: function(index) {
this.assertValidIndex_(index);
- var removed = this.cards_.splice(index, 1).pop();
+ const removed = this.cards_.splice(index, 1).pop();
- if (this.cards_.length == 0)
+ if (this.cards_.length == 0) {
this.currentCard_ = -1;
- else if (index < this.currentCard_)
+ } else if (index < this.currentCard_) {
this.selectCard(this.currentCard_ - 1, false, true);
+ }
this.fireRemovedEvent_(removed, index);
},
@@ -456,7 +466,7 @@ cr.define('cr.ui', function() {
* @private
*/
fireRemovedEvent_: function(card, index) {
- var e = document.createEvent('Event');
+ const e = document.createEvent('Event');
e.initEvent('cardSlider:card_removed', true, true);
e.removedCard = card;
e.removedIndex = index;
@@ -496,22 +506,23 @@ cr.define('cr.ui', function() {
newCardIndex, opt_animate, opt_dontNotify, opt_forceChange) {
this.assertValidIndex_(newCardIndex);
- var previousCard = this.currentCardValue;
- var isChangingCard =
+ const previousCard = this.currentCardValue;
+ let isChangingCard =
!this.cards_[newCardIndex].classList.contains('selected-card');
- if (typeof opt_forceChange != 'undefined' && opt_forceChange)
+ if (typeof opt_forceChange != 'undefined' && opt_forceChange) {
isChangingCard = true;
+ }
if (isChangingCard) {
this.currentCard_ = newCardIndex;
this.updateSelectedCardAttributes_();
}
- var willTransitionHappen = this.transformToCurrentCard_(opt_animate);
+ const willTransitionHappen = this.transformToCurrentCard_(opt_animate);
if (isChangingCard && !opt_dontNotify) {
- var event = document.createEvent('Event');
+ const event = document.createEvent('Event');
event.initEvent('cardSlider:card_changed', true, true);
event.cardSlider = this;
event.wasAnimated = !!opt_animate;
@@ -539,7 +550,7 @@ cr.define('cr.ui', function() {
* @param {boolean=} opt_animate Whether to animate.
*/
selectCardByValue: function(newCard, opt_animate) {
- var i = this.cards_.indexOf(newCard);
+ const i = this.cards_.indexOf(newCard);
assert(i != -1);
this.selectCard(i, opt_animate);
},
@@ -553,20 +564,21 @@ cr.define('cr.ui', function() {
* @private
*/
transformToCurrentCard_: function(opt_animate) {
- var prevLeft = this.currentLeft_;
+ const prevLeft = this.currentLeft_;
this.currentLeft_ = -this.cardWidth_ *
(isRTL() ? this.cards_.length - this.currentCard - 1 :
this.currentCard);
// If there's no change, return something to let the caller know there
// won't be a transition occuring.
- if (prevLeft == this.currentLeft_ && this.deltaX_ == 0)
+ if (prevLeft == this.currentLeft_ && this.deltaX_ == 0) {
return false;
+ }
// Animate to the current card, which will either transition if the
// current card is new, or reset the existing card if we didn't drag
// enough to change cards.
- var transition = '';
+ let transition = '';
if (opt_animate) {
transition =
'transform ' + CardSlider.TRANSITION_TIME_ + 'ms ease-in-out';
@@ -625,7 +637,7 @@ cr.define('cr.ui', function() {
*/
onDragMove_: function(e) {
e = /** @type {!cr.ui.TouchHandler.Event} */ (e);
- var deltaX = e.dragDeltaX;
+ let deltaX = e.dragDeltaX;
// If dragging beyond the first or last card then apply a backoff so the
// dragging feels stickier than usual.
if (!this.currentCard && deltaX > 0 ||
@@ -643,10 +655,10 @@ cr.define('cr.ui', function() {
*/
onDragEnd_: function(e) {
e = /** @type {!cr.ui.TouchHandler.Event} */ (e);
- var deltaX = e.dragDeltaX;
- var velocity = this.touchHandler_.getEndVelocity().x;
- var newX = this.currentLeft_ + deltaX;
- var newCardIndex = Math.round(-newX / this.cardWidth_);
+ const deltaX = e.dragDeltaX;
+ const velocity = this.touchHandler_.getEndVelocity().x;
+ const newX = this.currentLeft_ + deltaX;
+ let newCardIndex = Math.round(-newX / this.cardWidth_);
if (newCardIndex == this.currentCard &&
Math.abs(velocity) > CardSlider.TRANSITION_VELOCITY_THRESHOLD_) {
@@ -658,10 +670,11 @@ cr.define('cr.ui', function() {
// Ensure that the new card index is valid. The new card index could be
// invalid if a swipe suggests scrolling off the end of the list of
// cards.
- if (newCardIndex < 0)
+ if (newCardIndex < 0) {
newCardIndex = 0;
- else if (newCardIndex >= this.cardCount)
+ } else if (newCardIndex >= this.cardCount) {
newCardIndex = this.cardCount - 1;
+ }
this.selectCard(newCardIndex, /* animate */ true);
},
diff --git a/chromium/ui/webui/resources/js/cr/ui/command.js b/chromium/ui/webui/resources/js/cr/ui/command.js
index e2bd5193b33..9559c8982dc 100644
--- a/chromium/ui/webui/resources/js/cr/ui/command.js
+++ b/chromium/ui/webui/resources/js/cr/ui/command.js
@@ -27,7 +27,7 @@ cr.define('cr.ui', function() {
this.useKeyCode_ = false;
this.mods_ = {};
shortcut.split('|').forEach((part) => {
- var partLc = part.toLowerCase();
+ const partLc = part.toLowerCase();
switch (partLc) {
case 'alt':
case 'ctrl':
@@ -36,8 +36,9 @@ cr.define('cr.ui', function() {
this.mods_[partLc + 'Key'] = true;
break;
default:
- if (this.key_)
+ if (this.key_) {
throw Error('Invalid shortcut');
+ }
this.key_ = part;
// For single key alpha shortcuts use event.keyCode rather than
// event.key to match how chrome handles shortcuts and allow
@@ -60,7 +61,7 @@ cr.define('cr.ui', function() {
if ((this.useKeyCode_ && e.keyCode == this.keyCode_) ||
e.key == this.key_) {
// All keyboard modifiers need to match.
- var mods = this.mods_;
+ const mods = this.mods_;
return ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'].every(function(k) {
return e[k] == !!mods[k];
});
@@ -100,7 +101,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var Command = cr.ui.define('command');
+ const Command = cr.ui.define('command');
Command.prototype = {
__proto__: HTMLElement.prototype,
@@ -111,8 +112,9 @@ cr.define('cr.ui', function() {
decorate: function() {
CommandManager.init(assert(this.ownerDocument));
- if (this.hasAttribute('shortcut'))
+ if (this.hasAttribute('shortcut')) {
this.shortcut = this.getAttribute('shortcut');
+ }
},
/**
@@ -122,11 +124,12 @@ cr.define('cr.ui', function() {
* @param {HTMLElement=} opt_element Optional element to dispatch event on.
*/
execute: function(opt_element) {
- if (this.disabled)
+ if (this.disabled) {
return;
- var doc = this.ownerDocument;
+ }
+ const doc = this.ownerDocument;
if (doc.activeElement) {
- var e = new Event('command', {bubbles: true});
+ const e = new Event('command', {bubbles: true});
e.command = this;
(opt_element || doc.activeElement).dispatchEvent(e);
@@ -164,7 +167,7 @@ cr.define('cr.ui', function() {
return this.shortcut_;
},
set shortcut(shortcut) {
- var oldShortcut = this.shortcut_;
+ const oldShortcut = this.shortcut_;
if (shortcut !== oldShortcut) {
this.keyboardShortcuts_ = new KeyboardShortcutList(shortcut);
@@ -181,8 +184,9 @@ cr.define('cr.ui', function() {
* @return {boolean} Whether it matched or not.
*/
matchesEvent: function(e) {
- if (!this.keyboardShortcuts_)
+ if (!this.keyboardShortcuts_) {
return false;
+ }
return this.keyboardShortcuts_.matchesEvent(e);
},
};
@@ -222,7 +226,7 @@ cr.define('cr.ui', function() {
* @param {EventTarget} target The target element to dispatch the event on.
*/
function dispatchCanExecuteEvent(command, target) {
- var e = new CanExecuteEvent(command);
+ const e = new CanExecuteEvent(command);
target.dispatchEvent(e);
command.disabled = !e.canExecute;
}
@@ -230,7 +234,7 @@ cr.define('cr.ui', function() {
/**
* The command managers for different documents.
*/
- var commandManagers = {};
+ const commandManagers = {};
/**
* Keeps track of the focused element and updates the commands when the focus
@@ -250,7 +254,7 @@ cr.define('cr.ui', function() {
* @param {!Document} doc The document to manage the commands for.
*/
CommandManager.init = function(doc) {
- var uid = cr.getUid(doc);
+ const uid = cr.getUid(doc);
if (!(uid in commandManagers)) {
commandManagers[uid] = new CommandManager(doc);
}
@@ -266,13 +270,14 @@ cr.define('cr.ui', function() {
* TODO(vitalyp): remove the suppression.
*/
handleFocus_: function(e) {
- var target = e.target;
+ const target = e.target;
// Ignore focus on a menu button or command item.
- if (target.menu || target.command)
+ if (target.menu || target.command) {
return;
+ }
- var commands = Array.prototype.slice.call(
+ const commands = Array.prototype.slice.call(
target.ownerDocument.querySelectorAll('command'));
commands.forEach(function(command) {
@@ -285,11 +290,11 @@ cr.define('cr.ui', function() {
* @param {!Event} e The keydown event.
*/
handleKeyDown_: function(e) {
- var target = e.target;
- var commands = Array.prototype.slice.call(
+ const target = e.target;
+ const commands = Array.prototype.slice.call(
target.ownerDocument.querySelectorAll('command'));
- for (var i = 0, command; command = commands[i]; i++) {
+ for (let i = 0, command; command = commands[i]; i++) {
if (command.matchesEvent(e)) {
// When invoking a command via a shortcut, we have to manually check
// if it can be executed, since focus might not have been changed
@@ -316,7 +321,7 @@ cr.define('cr.ui', function() {
* @class
*/
function CanExecuteEvent(command) {
- var e = new Event('canExecute', {bubbles: true, cancelable: true});
+ const e = new Event('canExecute', {bubbles: true, cancelable: true});
e.__proto__ = CanExecuteEvent.prototype;
e.command = command;
return e;
diff --git a/chromium/ui/webui/resources/js/cr/ui/context_menu_button.js b/chromium/ui/webui/resources/js/cr/ui/context_menu_button.js
index a46c57d7468..1c1bd27307f 100644
--- a/chromium/ui/webui/resources/js/cr/ui/context_menu_button.js
+++ b/chromium/ui/webui/resources/js/cr/ui/context_menu_button.js
@@ -8,7 +8,7 @@
*/
cr.define('cr.ui', function() {
- /** @const */ var MenuButton = cr.ui.MenuButton;
+ /** @const */ const MenuButton = cr.ui.MenuButton;
/**
* Helper function for ContextMenuButton to find the first ancestor of the
@@ -17,7 +17,7 @@ cr.define('cr.ui', function() {
* @return {HTMLElement} The found element or null if not found.
*/
function getContextMenuTarget(button) {
- var el = button;
+ let el = button;
do {
el = el.parentNode;
} while (el && !('contextMenu' in el));
@@ -31,7 +31,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {cr.ui.MenuButton}
*/
- var ContextMenuButton = cr.ui.define('button');
+ const ContextMenuButton = cr.ui.define('button');
ContextMenuButton.prototype = {
__proto__: MenuButton.prototype,
@@ -42,7 +42,7 @@ cr.define('cr.ui', function() {
* @type {cr.ui.Menu}
*/
get menu() {
- var target = getContextMenuTarget(this);
+ const target = getContextMenuTarget(this);
return target && target.contextMenu;
},
@@ -58,9 +58,10 @@ cr.define('cr.ui', function() {
switch (e.type) {
case 'mousedown':
// Menu buttons prevent focus changes.
- var target = getContextMenuTarget(this);
- if (target)
+ const target = getContextMenuTarget(this);
+ if (target) {
target.focus();
+ }
break;
case 'mouseup':
// Stop mouseup to prevent selection changes.
@@ -81,7 +82,7 @@ cr.define('cr.ui', function() {
* @override
*/
showMenu: function(shouldSetFocus, opt_mousePos) {
- var self = this;
+ const self = this;
window.setTimeout(function() {
MenuButton.prototype.showMenu.call(self, shouldSetFocus, opt_mousePos);
}, 0);
diff --git a/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js b/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js
index ab07f6c19d7..9ae205ba112 100644
--- a/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js
+++ b/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js
@@ -5,8 +5,8 @@
// require: event_target.js
cr.define('cr.ui', function() {
- /** @const */ var EventTarget = cr.EventTarget;
- /** @const */ var Menu = cr.ui.Menu;
+ /** @const */ const EventTarget = cr.EventTarget;
+ /** @const */ const Menu = cr.ui.Menu;
/**
* Handles context menus.
@@ -39,8 +39,9 @@ cr.define('cr.ui', function() {
*/
showMenu: function(e, menu) {
menu.updateCommands(assertInstanceof(e.currentTarget, Node));
- if (!menu.hasVisibleItems())
+ if (!menu.hasVisibleItems()) {
return;
+ }
this.menu_ = menu;
menu.classList.remove('hide-delayed');
@@ -48,8 +49,8 @@ cr.define('cr.ui', function() {
menu.contextElement = e.currentTarget;
// When the menu is shown we steal a lot of events.
- var doc = menu.ownerDocument;
- var win = /** @type {!Window} */ (doc.defaultView);
+ const doc = menu.ownerDocument;
+ const win = /** @type {!Window} */ (doc.defaultView);
this.showingEvents_.add(doc, 'keydown', this, true);
this.showingEvents_.add(doc, 'mousedown', this, true);
this.showingEvents_.add(doc, 'touchstart', this, true);
@@ -61,7 +62,7 @@ cr.define('cr.ui', function() {
this.showingEvents_.add(menu, 'activate', this);
this.positionMenu_(e, menu);
- var ev = new Event('show');
+ const ev = new Event('show');
ev.element = menu.contextElement;
ev.menu = menu;
this.dispatchEvent(ev);
@@ -73,16 +74,18 @@ cr.define('cr.ui', function() {
* default: cr.ui.HideType.INSTANT.
*/
hideMenu: function(opt_hideType) {
- var menu = this.menu;
- if (!menu)
+ const menu = this.menu;
+ if (!menu) {
return;
+ }
- if (opt_hideType == cr.ui.HideType.DELAYED)
+ if (opt_hideType == cr.ui.HideType.DELAYED) {
menu.classList.add('hide-delayed');
- else
+ } else {
menu.classList.remove('hide-delayed');
+ }
menu.hide();
- var originalContextElement = menu.contextElement;
+ const originalContextElement = menu.contextElement;
menu.contextElement = null;
this.showingEvents_.removeAll();
menu.selectedIndex = -1;
@@ -93,7 +96,7 @@ cr.define('cr.ui', function() {
// to be shown again.
this.hideTimestamp_ = cr.isWindows ? Date.now() : 0;
- var ev = new Event('hide');
+ const ev = new Event('hide');
ev.element = originalContextElement;
ev.menu = menu;
this.dispatchEvent(ev);
@@ -108,15 +111,15 @@ cr.define('cr.ui', function() {
positionMenu_: function(e, menu) {
// TODO(arv): Handle scrolled documents when needed.
- var element = e.currentTarget;
- var x, y;
+ const element = e.currentTarget;
+ let x, y;
// When the user presses the context menu key (on the keyboard) we need
// to detect this.
if (this.keyIsDown_) {
- var rect = element.getRectForContextMenu ?
+ const rect = element.getRectForContextMenu ?
element.getRectForContextMenu() :
element.getBoundingClientRect();
- var offset = Math.min(rect.width, rect.height) / 2;
+ const offset = Math.min(rect.width, rect.height) / 2;
x = rect.left + offset;
y = rect.top + offset;
} else {
@@ -147,8 +150,9 @@ cr.define('cr.ui', function() {
}
// Context menu is handled even when we have no menu.
- if (e.type != 'contextmenu' && !this.menu)
+ if (e.type != 'contextmenu' && !this.menu) {
return;
+ }
switch (e.type) {
case 'mousedown':
@@ -160,13 +164,15 @@ cr.define('cr.ui', function() {
e.preventDefault();
e.stopPropagation();
}
- } else
+ } else {
e.preventDefault();
+ }
break;
case 'touchstart':
- if (!this.menu.contains(e.target))
+ if (!this.menu.contains(e.target)) {
this.hideMenu();
+ }
break;
case 'keydown':
@@ -184,15 +190,16 @@ cr.define('cr.ui', function() {
break;
case 'activate':
- var hideDelayed =
+ const hideDelayed =
e.target instanceof cr.ui.MenuItem && e.target.checkable;
this.hideMenu(
hideDelayed ? cr.ui.HideType.DELAYED : cr.ui.HideType.INSTANT);
break;
case 'focus':
- if (!this.menu.contains(e.target))
+ if (!this.menu.contains(e.target)) {
this.hideMenu();
+ }
break;
case 'blur':
@@ -206,8 +213,9 @@ cr.define('cr.ui', function() {
case 'contextmenu':
if ((!this.menu || !this.menu.contains(e.target)) &&
- (!this.hideTimestamp_ || Date.now() - this.hideTimestamp_ > 50))
+ (!this.hideTimestamp_ || Date.now() - this.hideTimestamp_ > 50)) {
this.showMenu(e, e.currentTarget.contextMenu);
+ }
e.preventDefault();
// Don't allow elements further up in the DOM to show their menus.
e.stopPropagation();
@@ -221,7 +229,7 @@ cr.define('cr.ui', function() {
* the contextMenu property to.
*/
addContextMenuProperty: function(elementOrClass) {
- var target = typeof elementOrClass == 'function' ?
+ const target = typeof elementOrClass == 'function' ?
elementOrClass.prototype :
elementOrClass;
@@ -229,15 +237,16 @@ cr.define('cr.ui', function() {
return this.contextMenu_;
});
target.__defineSetter__('contextMenu', function(menu) {
- var oldContextMenu = this.contextMenu;
+ const oldContextMenu = this.contextMenu;
if (typeof menu == 'string' && menu[0] == '#') {
menu = this.ownerDocument.getElementById(menu.slice(1));
cr.ui.decorate(menu, Menu);
}
- if (menu === oldContextMenu)
+ if (menu === oldContextMenu) {
return;
+ }
if (oldContextMenu && !menu) {
this.removeEventListener('contextmenu', contextMenuHandler);
@@ -252,8 +261,9 @@ cr.define('cr.ui', function() {
this.contextMenu_ = menu;
- if (menu && menu.id)
+ if (menu && menu.id) {
this.setAttribute('contextmenu', '#' + menu.id);
+ }
cr.dispatchPropertyChange(this, 'contextMenu', menu, oldContextMenu);
});
@@ -276,8 +286,9 @@ cr.define('cr.ui', function() {
* @param {!cr.ui.Menu} contextMenu The contextMenu property to be set.
*/
setContextMenu: function(element, contextMenu) {
- if (!element.contextMenu)
+ if (!element.contextMenu) {
this.addContextMenuProperty(element);
+ }
element.contextMenu = contextMenu;
}
};
@@ -286,7 +297,7 @@ cr.define('cr.ui', function() {
* The singleton context menu handler.
* @type {!ContextMenuHandler}
*/
- var contextMenuHandler = new ContextMenuHandler;
+ const contextMenuHandler = new ContextMenuHandler;
// Export
return {
diff --git a/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js b/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js
index a30d225a79e..eed723f5ad3 100644
--- a/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js
+++ b/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js
@@ -3,7 +3,7 @@
// found in the LICENSE file.
cr.define('cr.ui', function() {
- /** @const */ var BubbleButton = cr.ui.BubbleButton;
+ /** @const */ const BubbleButton = cr.ui.BubbleButton;
/**
* An indicator that can be placed on a UI element as a hint to the user that
@@ -12,14 +12,14 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {cr.ui.BubbleButton}
*/
- var ControlledIndicator = cr.ui.define('span');
+ const ControlledIndicator = cr.ui.define('span');
/**
* Only a single bubble can be shown at a time. |bubble| holds a reference to
* the bubble, if any.
* @private
*/
- var bubble;
+ let bubble;
ControlledIndicator.prototype = {
__proto__: cr.ui.BubbleButton.prototype,
@@ -51,8 +51,9 @@ cr.define('cr.ui', function() {
* Hides the currently visible bubble, if any.
*/
hideBubble: function() {
- if (bubble)
+ if (bubble) {
bubble.hide();
+ }
},
/**
@@ -72,13 +73,14 @@ cr.define('cr.ui', function() {
* @return {string}
*/
getBubbleText: function() {
- var defaultStrings = this.getDefaultStrings();
- var text = defaultStrings[this.controlledBy];
+ const defaultStrings = this.getDefaultStrings();
+ let text = defaultStrings[this.controlledBy];
- if (this.hasAttribute('text' + this.controlledBy))
+ if (this.hasAttribute('text' + this.controlledBy)) {
text = this.getAttribute('text' + this.controlledBy);
- else if (this.controlledBy == 'extension' && this['extensionName'])
+ } else if (this.controlledBy == 'extension' && this['extensionName']) {
text = defaultStrings['extensionWithName'];
+ }
return text || '';
},
@@ -88,7 +90,7 @@ cr.define('cr.ui', function() {
* @param {string} text to be shown in the bubble.
*/
createDomTree: function(text) {
- var content = document.createElement('div');
+ const content = document.createElement('div');
content.textContent = text;
return content;
},
@@ -98,10 +100,11 @@ cr.define('cr.ui', function() {
* @override
*/
toggleBubble: function() {
- if (this.showingBubble)
+ if (this.showingBubble) {
this.hideBubble();
- else
+ } else {
this.showBubble(this.createDomTree(this.getBubbleText()));
+ }
},
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/dialogs.js b/chromium/ui/webui/resources/js/cr/ui/dialogs.js
index 086560391fc..f18c5a378c0 100644
--- a/chromium/ui/webui/resources/js/cr/ui/dialogs.js
+++ b/chromium/ui/webui/resources/js/cr/ui/dialogs.js
@@ -40,7 +40,7 @@ cr.define('cr.ui.dialogs', function() {
/** @protected */
BaseDialog.prototype.initDom_ = function() {
- var doc = this.document_;
+ const doc = this.document_;
this.container_ = doc.createElement('div');
this.container_.className = 'cr-dialog-container';
this.container_.addEventListener(
@@ -112,7 +112,7 @@ cr.define('cr.ui.dialogs', function() {
/** @private */
BaseDialog.prototype.onContainerMouseDown_ = function(event) {
if (event.target == this.container_) {
- var classList = this.container_.classList;
+ const classList = this.container_.classList;
// Start 'pulse' animation.
classList.remove('pulse');
setTimeout(classList.add.bind(classList, 'pulse'), 0);
@@ -123,15 +123,17 @@ cr.define('cr.ui.dialogs', function() {
/** @private */
BaseDialog.prototype.onOkClick_ = function(event) {
this.hide();
- if (this.onOk_)
+ if (this.onOk_) {
this.onOk_();
+ }
};
/** @private */
BaseDialog.prototype.onCancelClick_ = function(event) {
this.hide();
- if (this.onCancel_)
+ if (this.onCancel_) {
this.onCancel_();
+ }
};
/** @param {string} label */
@@ -174,23 +176,24 @@ cr.define('cr.ui.dialogs', function() {
/** @private */
BaseDialog.prototype.findFocusableElements_ = function(doc) {
- var elements =
+ let elements =
Array.prototype.filter.call(doc.querySelectorAll('*'), function(n) {
return n.tabIndex >= 0;
});
- var iframes = doc.querySelectorAll('iframe');
- for (var i = 0; i < iframes.length; i++) {
+ const iframes = doc.querySelectorAll('iframe');
+ for (let i = 0; i < iframes.length; i++) {
// Some iframes have an undefined contentDocument for security reasons,
// such as chrome://terms (which is used in the chromeos OOBE screens).
- var iframe = iframes[i];
- var contentDoc;
+ const iframe = iframes[i];
+ let contentDoc;
try {
contentDoc = iframe.contentDocument;
} catch (e) {
} // ignore SecurityError
- if (contentDoc)
+ if (contentDoc) {
elements = elements.concat(this.findFocusableElements_(contentDoc));
+ }
}
return elements;
};
@@ -241,7 +244,7 @@ cr.define('cr.ui.dialogs', function() {
this.title_.hidden = true;
}
- var self = this;
+ const self = this;
setTimeout(function() {
// Check that hide() was not called in between.
if (self.showing_) {
@@ -249,8 +252,9 @@ cr.define('cr.ui.dialogs', function() {
self.initialFocusElement_.focus();
}
setTimeout(function() {
- if (opt_onShow)
+ if (opt_onShow) {
opt_onShow();
+ }
}, BaseDialog.ANIMATE_STABLE_DURATION);
}, 0);
};
@@ -259,12 +263,13 @@ cr.define('cr.ui.dialogs', function() {
BaseDialog.prototype.hide = function(opt_onHide) {
this.showing_ = false;
// Restore focusability.
- for (var i = 0; i < this.deactivatedNodes_.length; i++) {
- var node = this.deactivatedNodes_[i];
- if (this.tabIndexes_[i] === null)
+ for (let i = 0; i < this.deactivatedNodes_.length; i++) {
+ const node = this.deactivatedNodes_[i];
+ if (this.tabIndexes_[i] === null) {
node.removeAttribute('tabindex');
- else
+ } else {
node.setAttribute('tabindex', this.tabIndexes_[i]);
+ }
}
this.deactivatedNodes_ = null;
this.tabIndexes_ = null;
@@ -278,16 +283,18 @@ cr.define('cr.ui.dialogs', function() {
}
this.frame_.classList.remove('pulse');
- var self = this;
+ const self = this;
setTimeout(function() {
// Wait until the transition is done before removing the dialog.
// Check show() was not called in between.
// It is also possible to show/hide/show/hide and have hide called twice
// and container_ already removed from parentNode_.
- if (!self.showing_ && self.parentNode_ === self.container_.parentNode)
+ if (!self.showing_ && self.parentNode_ === self.container_.parentNode) {
self.parentNode_.removeChild(self.container_);
- if (opt_onHide)
+ }
+ if (opt_onHide) {
opt_onHide();
+ }
}, BaseDialog.ANIMATE_STABLE_DURATION);
};
@@ -378,8 +385,9 @@ cr.define('cr.ui.dialogs', function() {
/** @private */
PromptDialog.prototype.onOkClick_ = function(event) {
this.hide();
- if (this.onOk_)
+ if (this.onOk_) {
this.onOk_(this.getValue());
+ }
};
return {
diff --git a/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js b/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js
index 005814a960f..77e53d7fe76 100644
--- a/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js
+++ b/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js
@@ -9,7 +9,7 @@
*/
cr.define('cr.ui', function() {
/** @interface */
- var DragWrapperDelegate = function() {};
+ const DragWrapperDelegate = function() {};
// TODO(devlin): The only method this "delegate" actually needs is
// shouldAcceptDrag(); the rest can be events emitted by the DragWrapper.
@@ -103,8 +103,9 @@ cr.define('cr.ui', function() {
* @private
*/
onDragOver_: function(e) {
- if (!this.target_.classList.contains('drag-target'))
+ if (!this.target_.classList.contains('drag-target')) {
return;
+ }
this.delegate_.doDragOver(e);
},
@@ -115,8 +116,9 @@ cr.define('cr.ui', function() {
*/
onDrop_: function(e) {
this.dragEnters_ = 0;
- if (!this.target_.classList.contains('drag-target'))
+ if (!this.target_.classList.contains('drag-target')) {
return;
+ }
this.target_.classList.remove('drag-target');
this.delegate_.doDrop(e);
},
@@ -127,8 +129,9 @@ cr.define('cr.ui', function() {
* @private
*/
onDragLeave_: function(e) {
- if (--this.dragEnters_ > 0)
+ if (--this.dragEnters_ > 0) {
return;
+ }
this.target_.classList.remove('drag-target');
this.delegate_.doDragLeave(e);
diff --git a/chromium/ui/webui/resources/js/cr/ui/expandable_bubble.js b/chromium/ui/webui/resources/js/cr/ui/expandable_bubble.js
index 88440794449..2c8f97094a9 100644
--- a/chromium/ui/webui/resources/js/cr/ui/expandable_bubble.js
+++ b/chromium/ui/webui/resources/js/cr/ui/expandable_bubble.js
@@ -18,7 +18,7 @@ cr.define('cr.ui', function() {
* @extends {HTMLDivElement}
* @implements {EventListener}
*/
- var ExpandableBubble = cr.ui.define('div');
+ const ExpandableBubble = cr.ui.define('div');
ExpandableBubble.prototype = {
__proto__: HTMLDivElement.prototype,
@@ -42,7 +42,7 @@ cr.define('cr.ui', function() {
* @param {Node} node An HTML element to set as the title.
*/
set contentTitle(node) {
- var bubbleTitle = this.querySelector('.expandable-bubble-title');
+ const bubbleTitle = this.querySelector('.expandable-bubble-title');
bubbleTitle.textContent = '';
bubbleTitle.appendChild(node);
},
@@ -53,7 +53,7 @@ cr.define('cr.ui', function() {
* @param {Node} node An HTML element.
*/
set content(node) {
- var bubbleMain = this.querySelector('.expandable-bubble-main');
+ const bubbleMain = this.querySelector('.expandable-bubble-main');
bubbleMain.textContent = '';
bubbleMain.appendChild(node);
},
@@ -66,8 +66,9 @@ cr.define('cr.ui', function() {
set anchorNode(node) {
this.anchorNode_ = node;
- if (!this.hidden)
+ if (!this.hidden) {
this.resizeAndReposition();
+ }
},
/**
@@ -92,8 +93,9 @@ cr.define('cr.ui', function() {
set suppressed(suppress) {
if (suppress) {
// If the bubble is already hidden, then we don't need to suppress it.
- if (this.hidden)
+ if (this.hidden) {
return;
+ }
this.hidden = true;
} else if (this.bubbleSuppressed) {
@@ -108,16 +110,17 @@ cr.define('cr.ui', function() {
* @private
*/
reposition_: function() {
- var clientRect = this.anchorNode_.getBoundingClientRect();
+ const clientRect = this.anchorNode_.getBoundingClientRect();
// Center bubble in collapsed mode (if it doesn't take up all the room we
// have).
- var offset = 0;
- if (!this.expanded)
+ let offset = 0;
+ if (!this.expanded) {
offset = (clientRect.width - parseInt(this.style.width, 10)) / 2;
+ }
this.style.left = this.style.right = clientRect.left + offset + 'px';
- var top = Math.max(0, clientRect.top - 4);
+ const top = Math.max(0, clientRect.top - 4);
this.style.top = this.expanded ?
(top - this.offsetHeight + this.unexpandedHeight) + 'px' :
top + 'px';
@@ -128,13 +131,13 @@ cr.define('cr.ui', function() {
* @private
*/
resizeAndReposition: function() {
- var clientRect = this.anchorNode_.getBoundingClientRect();
- var width = clientRect.width;
+ const clientRect = this.anchorNode_.getBoundingClientRect();
+ let width = clientRect.width;
- var bubbleTitle = this.querySelector('.expandable-bubble-title');
- var closeElement = this.querySelector('.expandable-bubble-close');
- var closeWidth = this.expanded ? closeElement.clientWidth : 0;
- var margin = 15;
+ const bubbleTitle = this.querySelector('.expandable-bubble-title');
+ const closeElement = this.querySelector('.expandable-bubble-close');
+ const closeWidth = this.expanded ? closeElement.clientWidth : 0;
+ const margin = 15;
// Suppress the width style so we can get it to calculate its width.
// We'll set the right width again when we are done.
@@ -143,12 +146,12 @@ cr.define('cr.ui', function() {
if (this.expanded) {
// We always show the full title but never show less width than 250
// pixels.
- var expandedWidth =
+ const expandedWidth =
Math.max(250, bubbleTitle.scrollWidth + closeWidth + margin);
this.style.marginLeft = (width - expandedWidth) + 'px';
width = expandedWidth;
} else {
- var newWidth = Math.min(bubbleTitle.scrollWidth + margin, width);
+ const newWidth = Math.min(bubbleTitle.scrollWidth + margin, width);
// If we've maxed out in width then apply the mask.
this.masked = newWidth == width;
width = newWidth;
@@ -196,8 +199,9 @@ cr.define('cr.ui', function() {
* Node.prototype.contains() will be fixed.
*/
onNotificationClick_: function(e) {
- if (!this.contains(/** @type {!Node} */ (e.target)))
+ if (!this.contains(/** @type {!Node} */ (e.target))) {
return;
+ }
if (!this.expanded) {
// Save the height of the unexpanded bubble, so we can make sure to
@@ -214,8 +218,9 @@ cr.define('cr.ui', function() {
* clicked.
*/
show: function() {
- if (!this.hidden)
+ if (!this.hidden) {
return;
+ }
document.body.appendChild(this);
this.hidden = false;
@@ -228,7 +233,7 @@ cr.define('cr.ui', function() {
window, 'resize', this.resizeAndReposition.bind(this));
this.eventTracker_.add(this, 'click', this.onNotificationClick_);
- var doc = this.ownerDocument;
+ const doc = this.ownerDocument;
this.eventTracker_.add(assert(doc), 'keydown', this, true);
this.eventTracker_.add(assert(doc), 'mousedown', this, true);
},
@@ -253,7 +258,7 @@ cr.define('cr.ui', function() {
* Node.prototype.contains() will be fixed.
*/
handleEvent: function(e) {
- var handled = false;
+ let handled = false;
switch (e.type) {
case 'keydown':
if (e.keyCode == 27) { // Esc.
diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_grid.js b/chromium/ui/webui/resources/js/cr/ui/focus_grid.js
index de710112a36..7b86854d069 100644
--- a/chromium/ui/webui/resources/js/cr/ui/focus_grid.js
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_grid.js
@@ -38,10 +38,11 @@ cr.define('cr.ui', function() {
/** @override */
onFocus: function(row, e) {
- if (this.ignoreFocusChange_)
+ if (this.ignoreFocusChange_) {
this.ignoreFocusChange_ = false;
- else
+ } else {
this.lastFocused_ = e.currentTarget;
+ }
this.rows.forEach(function(r) {
r.makeActive(r == row);
@@ -50,21 +51,22 @@ cr.define('cr.ui', function() {
/** @override */
onKeydown: function(row, e) {
- var rowIndex = this.rows.indexOf(row);
+ const rowIndex = this.rows.indexOf(row);
assert(rowIndex >= 0);
- var newRow = -1;
+ let newRow = -1;
- if (e.key == 'ArrowUp')
+ if (e.key == 'ArrowUp') {
newRow = rowIndex - 1;
- else if (e.key == 'ArrowDown')
+ } else if (e.key == 'ArrowDown') {
newRow = rowIndex + 1;
- else if (e.key == 'PageUp')
+ } else if (e.key == 'PageUp') {
newRow = 0;
- else if (e.key == 'PageDown')
+ } else if (e.key == 'PageDown') {
newRow = this.rows.length - 1;
+ }
- var rowToFocus = this.rows[newRow];
+ const rowToFocus = this.rows[newRow];
if (rowToFocus) {
this.ignoreFocusChange_ = true;
rowToFocus.getEquivalentElement(this.lastFocused_).focus();
@@ -75,6 +77,11 @@ cr.define('cr.ui', function() {
return false;
},
+ /** @override */
+ getCustomEquivalent: function(sampleElement) {
+ return null;
+ },
+
/**
* Unregisters event handlers and removes all |this.rows|.
*/
@@ -90,9 +97,10 @@ cr.define('cr.ui', function() {
* @return {number} The row index. -1 if not found.
*/
getRowIndexForTarget: function(target) {
- for (var i = 0; i < this.rows.length; ++i) {
- if (this.rows[i].getElements().indexOf(target) >= 0)
+ for (let i = 0; i < this.rows.length; ++i) {
+ if (this.rows[i].getElements().indexOf(target) >= 0) {
return i;
+ }
}
return -1;
},
@@ -102,9 +110,10 @@ cr.define('cr.ui', function() {
* @return {?cr.ui.FocusRow} The row with root of |root| or null.
*/
getRowForRoot: function(root) {
- for (var i = 0; i < this.rows.length; ++i) {
- if (this.rows[i].root == root)
+ for (let i = 0; i < this.rows.length; ++i) {
+ if (this.rows[i].root == root) {
return this.rows[i];
+ }
}
return null;
},
@@ -126,11 +135,12 @@ cr.define('cr.ui', function() {
addRowBefore: function(row, nextRow) {
row.delegate = row.delegate || this;
- var nextRowIndex = nextRow ? this.rows.indexOf(nextRow) : -1;
- if (nextRowIndex == -1)
+ const nextRowIndex = nextRow ? this.rows.indexOf(nextRow) : -1;
+ if (nextRowIndex == -1) {
this.rows.push(row);
- else
+ } else {
this.rows.splice(nextRowIndex, 0, row);
+ }
},
/**
@@ -138,9 +148,10 @@ cr.define('cr.ui', function() {
* @param {cr.ui.FocusRow} row The row that needs to be removed.
*/
removeRow: function(row) {
- var nextRowIndex = row ? this.rows.indexOf(row) : -1;
- if (nextRowIndex > -1)
+ const nextRowIndex = row ? this.rows.indexOf(row) : -1;
+ if (nextRowIndex > -1) {
this.rows.splice(nextRowIndex, 1);
+ }
},
/**
@@ -151,12 +162,14 @@ cr.define('cr.ui', function() {
* grid.
*/
ensureRowActive: function(preferredRow) {
- if (this.rows.length == 0)
+ if (this.rows.length == 0) {
return;
+ }
- for (var i = 0; i < this.rows.length; ++i) {
- if (this.rows[i].isActive())
+ for (let i = 0; i < this.rows.length; ++i) {
+ if (this.rows[i].isActive()) {
return;
+ }
}
(this.rows[preferredRow || 0] || this.rows[0]).makeActive(true);
diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_manager.js b/chromium/ui/webui/resources/js/cr/ui/focus_manager.js
index e2c8347de49..eb79a526478 100644
--- a/chromium/ui/webui/resources/js/cr/ui/focus_manager.js
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_manager.js
@@ -45,15 +45,15 @@ cr.define('cr.ui', function() {
* @return {Array<Element>} The focusable elements.
*/
getFocusableElements_: function() {
- var focusableDiv = this.getFocusParent();
+ const focusableDiv = this.getFocusParent();
// Create a TreeWalker object to traverse the DOM from |focusableDiv|.
- var treeWalker = document.createTreeWalker(
+ const treeWalker = document.createTreeWalker(
focusableDiv, NodeFilter.SHOW_ELEMENT,
/** @type {NodeFilter} */
({
acceptNode: function(node) {
- var style = window.getComputedStyle(node);
+ const style = window.getComputedStyle(node);
// Reject all hidden nodes. FILTER_REJECT also rejects these
// nodes' children, so non-hidden elements that are descendants of
// hidden <div>s will correctly be rejected.
@@ -64,8 +64,9 @@ cr.define('cr.ui', function() {
// Skip nodes that cannot receive focus. FILTER_SKIP does not
// cause this node's children also to be skipped.
- if (node.disabled || node.tabIndex < 0)
+ if (node.disabled || node.tabIndex < 0) {
return NodeFilter.FILTER_SKIP;
+ }
// Accept nodes that are non-hidden and focusable.
return NodeFilter.FILTER_ACCEPT;
@@ -73,9 +74,10 @@ cr.define('cr.ui', function() {
}),
false);
- var focusable = [];
- while (treeWalker.nextNode())
+ const focusable = [];
+ while (treeWalker.nextNode()) {
focusable.push(treeWalker.currentNode);
+ }
return focusable;
},
@@ -99,7 +101,7 @@ cr.define('cr.ui', function() {
* @private
*/
setFocus_: function() {
- var element = this.selectFocusableElement_();
+ const element = this.selectFocusableElement_();
if (element) {
element.focus();
this.dispatchFocusEvent_(element);
@@ -118,18 +120,19 @@ cr.define('cr.ui', function() {
// current dialog. In this case, loop around and try to focus the last
// element of the dialog; otherwise, try to focus the first element of the
// dialog.
- var focusableElements = this.getFocusableElements_();
- var element = this.focusDirBackwards_ ? focusableElements.pop() :
+ const focusableElements = this.getFocusableElements_();
+ let element = this.focusDirBackwards_ ? focusableElements.pop() :
focusableElements.shift();
- if (!element)
+ if (!element) {
return null;
+ }
if (element.tagName != 'INPUT' || element.type != 'radio' ||
element.name == '') {
return element;
}
if (!element.checked) {
- for (var i = 0; i < focusableElements.length; i++) {
- var e = focusableElements[i];
+ for (let i = 0; i < focusableElements.length; i++) {
+ const e = focusableElements[i];
if (e && e.tagName == 'INPUT' && e.type == 'radio' &&
e.name == element.name && e.checked) {
element = e;
@@ -148,7 +151,7 @@ cr.define('cr.ui', function() {
onDocumentFocus_: function(event) {
// If the element being focused is a descendant of the currently visible
// page, focus is valid.
- var targetNode = /** @type {Node} */ (event.target);
+ const targetNode = /** @type {Node} */ (event.target);
if (this.isDescendantOf_(this.getFocusParent(), targetNode)) {
this.dispatchFocusEvent_(event.target);
return;
@@ -172,7 +175,7 @@ cr.define('cr.ui', function() {
* @private
*/
onDocumentKeyDown_: function(event) {
- /** @const */ var tabKeyCode = 9;
+ /** @const */ const tabKeyCode = 9;
if (event.keyCode == tabKeyCode) {
// If the "Shift" key is held, focus is being transferred backward in
diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js b/chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js
index 604a2cb9e83..3432f1e60ba 100644
--- a/chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js
@@ -7,7 +7,7 @@ cr.define('cr.ui', function() {
* The class name to set on the document element.
* @const
*/
- var CLASS_NAME = 'focus-outline-visible';
+ const CLASS_NAME = 'focus-outline-visible';
/**
* This class sets a CSS class name on the HTML element of |doc| when the user
@@ -29,9 +29,10 @@ cr.define('cr.ui', function() {
function FocusOutlineManager(doc) {
this.classList_ = doc.documentElement.classList;
- var onEvent = function(focusByKeyboard, e) {
- if (this.focusByKeyboard_ === focusByKeyboard)
+ const onEvent = function(focusByKeyboard, e) {
+ if (this.focusByKeyboard_ === focusByKeyboard) {
return;
+ }
this.focusByKeyboard_ = focusByKeyboard;
this.updateVisibility();
};
@@ -76,7 +77,7 @@ cr.define('cr.ui', function() {
};
/** @type {!Map<!Document, !cr.ui.FocusOutlineManager>} */
- var docsToManager = new Map();
+ const docsToManager = new Map();
/**
* Gets a per document singleton focus outline manager.
@@ -85,7 +86,7 @@ cr.define('cr.ui', function() {
* outline manager.
*/
FocusOutlineManager.forDocument = function(doc) {
- var manager = docsToManager.get(doc);
+ let manager = docsToManager.get(doc);
if (!manager) {
manager = new FocusOutlineManager(doc);
docsToManager.set(doc, manager);
diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_row.js b/chromium/ui/webui/resources/js/cr/ui/focus_row.js
index 8915b114a4a..cf8583c0dab 100644
--- a/chromium/ui/webui/resources/js/cr/ui/focus_row.js
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_row.js
@@ -44,8 +44,9 @@ cr.define('cr.ui', function() {
* @return {boolean} Whether the item is focusable.
*/
static isFocusable(element) {
- if (!element || element.disabled)
+ if (!element || element.disabled) {
return false;
+ }
// We don't check that element.tabIndex >= 0 here because inactive rows
// set a tabIndex of -1.
@@ -53,17 +54,20 @@ cr.define('cr.ui', function() {
while (true) {
assertInstanceof(current, Element);
- var style = window.getComputedStyle(current);
- if (style.visibility == 'hidden' || style.display == 'none')
+ const style = window.getComputedStyle(current);
+ if (style.visibility == 'hidden' || style.display == 'none') {
return false;
+ }
- var parent = current.parentNode;
- if (!parent)
+ const parent = current.parentNode;
+ if (!parent) {
return false;
+ }
if (parent == current.ownerDocument ||
- parent instanceof DocumentFragment)
+ parent instanceof DocumentFragment) {
return true;
+ }
current = /** @type {Element} */ (parent);
}
@@ -79,8 +83,9 @@ cr.define('cr.ui', function() {
* @return {!Element}
*/
static getFocusableElement(element) {
- if (element.getFocusableElement)
+ if (element.getFocusableElement) {
return element.getFocusableElement();
+ }
return element;
}
@@ -104,13 +109,15 @@ cr.define('cr.ui', function() {
addItem(type, selectorOrElement) {
assert(type);
- var element;
- if (typeof selectorOrElement == 'string')
+ let element;
+ if (typeof selectorOrElement == 'string') {
element = this.root.querySelector(selectorOrElement);
- else
+ } else {
element = selectorOrElement;
- if (!element)
+ }
+ if (!element) {
return false;
+ }
element.setAttribute('focus-type', type);
element.tabIndex = this.isActive() ? 0 : -1;
@@ -152,14 +159,16 @@ cr.define('cr.ui', function() {
* @return {!Element} The element that best matches sampleElement.
*/
getEquivalentElement(sampleElement) {
- if (this.getFocusableElements().indexOf(sampleElement) >= 0)
+ if (this.getFocusableElements().indexOf(sampleElement) >= 0) {
return sampleElement;
+ }
- var sampleFocusType = this.getTypeForElement(sampleElement);
+ const sampleFocusType = this.getTypeForElement(sampleElement);
if (sampleFocusType) {
- var sameType = this.getFirstFocusable(sampleFocusType);
- if (sameType)
+ const sameType = this.getFirstFocusable(sampleFocusType);
+ if (sameType) {
return sameType;
+ }
}
return this.getCustomEquivalent(sampleElement);
@@ -199,8 +208,9 @@ cr.define('cr.ui', function() {
* @param {boolean} active True if tab is allowed for this row.
*/
makeActive(active) {
- if (active == this.isActive())
+ if (active == this.isActive()) {
return;
+ }
this.getElements().forEach(function(element) {
element.tabIndex = active ? 0 : -1;
@@ -214,12 +224,14 @@ cr.define('cr.ui', function() {
* @private
*/
onBlur_(e) {
- if (!this.boundary_.contains(/** @type {Element} */ (e.relatedTarget)))
+ if (!this.boundary_.contains(/** @type {Element} */ (e.relatedTarget))) {
return;
+ }
- var currentTarget = /** @type {!Element} */ (e.currentTarget);
- if (this.getFocusableElements().indexOf(currentTarget) >= 0)
+ const currentTarget = /** @type {!Element} */ (e.currentTarget);
+ if (this.getFocusableElements().indexOf(currentTarget) >= 0) {
this.makeActive(false);
+ }
}
/**
@@ -227,8 +239,9 @@ cr.define('cr.ui', function() {
* @private
*/
onFocus_(e) {
- if (this.delegate)
+ if (this.delegate) {
this.delegate.onFocus(this, e);
+ }
}
/**
@@ -237,12 +250,14 @@ cr.define('cr.ui', function() {
*/
onMousedown_(e) {
// Only accept left mouse clicks.
- if (e.button)
+ if (e.button) {
return;
+ }
// Allow the element under the mouse cursor to be focusable.
- if (!e.currentTarget.disabled)
+ if (!e.currentTarget.disabled) {
e.currentTarget.tabIndex = 0;
+ }
}
/**
@@ -250,29 +265,32 @@ cr.define('cr.ui', function() {
* @private
*/
onKeydown_(e) {
- var elements = this.getFocusableElements();
- var currentElement = /** @type {!Element} */ (e.currentTarget);
- var elementIndex = elements.indexOf(currentElement);
+ const elements = this.getFocusableElements();
+ const currentElement = /** @type {!Element} */ (e.currentTarget);
+ const elementIndex = elements.indexOf(currentElement);
assert(elementIndex >= 0);
- if (this.delegate && this.delegate.onKeydown(this, e))
+ if (this.delegate && this.delegate.onKeydown(this, e)) {
return;
+ }
- if (hasKeyModifiers(e))
+ if (hasKeyModifiers(e)) {
return;
+ }
- var index = -1;
+ let index = -1;
- if (e.key == 'ArrowLeft')
+ if (e.key == 'ArrowLeft') {
index = elementIndex + (isRTL() ? 1 : -1);
- else if (e.key == 'ArrowRight')
+ } else if (e.key == 'ArrowRight') {
index = elementIndex + (isRTL() ? -1 : 1);
- else if (e.key == 'Home')
+ } else if (e.key == 'Home') {
index = 0;
- else if (e.key == 'End')
+ } else if (e.key == 'End') {
index = elements.length - 1;
+ }
- var elementToFocus = elements[index];
+ const elementToFocus = elements[index];
if (elementToFocus) {
this.getEquivalentElement(elementToFocus).focus();
e.preventDefault();
@@ -300,6 +318,13 @@ cr.define('cr.ui', function() {
* @param {!Event} e
*/
onFocus(row, e) {}
+
+ /**
+ * @param {!Element} sampleElement An element to find an equivalent for.
+ * @return {?Element} An equivalent element to focus, or null to use the
+ * default FocusRow element.
+ */
+ getCustomEquivalent(sampleElement) {}
}
return {
diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js b/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js
new file mode 100644
index 00000000000..f8f625f5c65
--- /dev/null
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js
@@ -0,0 +1,327 @@
+// 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.
+
+cr.define('cr.ui', function() {
+ /** @implements {cr.ui.FocusRowDelegate} */
+ class FocusRowBehaviorDelegate {
+ /**
+ * @param {{lastFocused: Object,
+ * overrideCustomEquivalent: boolean,
+ * getCustomEquivalent: (Function|undefined)}} listItem
+ */
+ constructor(listItem) {
+ /** @private */
+ this.listItem_ = listItem;
+ }
+
+ /**
+ * This function gets called when the [focus-row-control] element receives
+ * the focus event.
+ * @override
+ * @param {!cr.ui.FocusRow} row
+ * @param {!Event} e
+ */
+ onFocus(row, e) {
+ this.listItem_.lastFocused = e.path[0];
+ }
+
+ /**
+ * @override
+ * @param {!cr.ui.FocusRow} row The row that detected a keydown.
+ * @param {!Event} e
+ * @return {boolean} Whether the event was handled.
+ */
+ onKeydown(row, e) {
+ // Prevent iron-list from changing the focus on enter.
+ if (e.key == 'Enter') {
+ e.stopPropagation();
+ }
+
+ return false;
+ }
+
+ /** @override */
+ getCustomEquivalent(sampleElement) {
+ return this.listItem_.overrideCustomEquivalent ?
+ this.listItem_.getCustomEquivalent(sampleElement) :
+ null;
+ }
+ }
+
+ /** @extends {cr.ui.FocusRow} */
+ class VirtualFocusRow extends cr.ui.FocusRow {
+ /**
+ * @param {!Element} root
+ * @param {cr.ui.FocusRowDelegate} delegate
+ */
+ constructor(root, delegate) {
+ super(root, /* boundary */ null, delegate);
+ }
+
+ /** @override */
+ getCustomEquivalent(sampleElement) {
+ return this.delegate.getCustomEquivalent(sampleElement) ||
+ super.getCustomEquivalent(sampleElement);
+ }
+ }
+
+ /**
+ * Any element that is being used as an iron-list row item can extend this
+ * behavior, which encapsulates focus controls of mouse and keyboards.
+ * To use this behavior:
+ * - The parent element should pass a "last-focused" attribute double-bound
+ * to the row items, to track the last-focused element across rows, and
+ * a "list-blurred" attribute double-bound to the row items, to track
+ * whether the list of row items has been blurred.
+ * - There must be a container in the extending element with the
+ * [focus-row-container] attribute that contains all focusable controls.
+ * - On each of the focusable controls, there must be a [focus-row-control]
+ * attribute, and a [focus-type=] attribute unique for each control.
+ *
+ * @polymerBehavior
+ */
+ const FocusRowBehavior = {
+ properties: {
+ /** @private {cr.ui.VirtualFocusRow} */
+ row_: Object,
+
+ /** @private {boolean} */
+ mouseFocused_: Boolean,
+
+ /** @type {Element} */
+ lastFocused: {
+ type: Object,
+ notify: true,
+ },
+
+ /**
+ * This is different from tabIndex, since the template only does a one-way
+ * binding on both attributes, and the behavior actually make use of this
+ * fact. For example, when a control within a row is focused, it will have
+ * tabIndex = -1 and ironListTabIndex = 0.
+ * @type {number}
+ */
+ ironListTabIndex: {
+ type: Number,
+ observer: 'ironListTabIndexChanged_',
+ },
+
+ listBlurred: {
+ type: Boolean,
+ notify: true,
+ },
+ },
+
+ /** @private {?Element} */
+ firstControl_: null,
+
+ /** @private {!Array<!MutationObserver>} */
+ controlObservers_: [],
+
+ /** @override */
+ attached: function() {
+ this.classList.add('no-outline');
+
+ Polymer.RenderStatus.afterNextRender(this, function() {
+ const rowContainer = this.root.querySelector('[focus-row-container]');
+ assert(!!rowContainer);
+ this.row_ = new VirtualFocusRow(
+ rowContainer, new FocusRowBehaviorDelegate(this));
+ this.ironListTabIndexChanged_();
+ this.addItems_();
+
+ // Adding listeners asynchronously to reduce blocking time, since this
+ // behavior will be used by items in potentially long lists.
+ this.listen(this, 'focus', 'onFocus_');
+ this.listen(this, 'dom-change', 'addItems_');
+ this.listen(this, 'mousedown', 'onMouseDown_');
+ this.listen(this, 'blur', 'onBlur_');
+ });
+ },
+
+ /** @override */
+ detached: function() {
+ this.unlisten(this, 'focus', 'onFocus_');
+ this.unlisten(this, 'dom-change', 'addItems_');
+ this.unlisten(this, 'mousedown', 'onMouseDown_');
+ this.unlisten(this, 'blur', 'onBlur_');
+ this.removeObservers_();
+ if (this.row_) {
+ this.row_.destroy();
+ }
+ },
+
+ /** @private */
+ updateFirstControl_: function() {
+ const newFirstControl = this.row_.getFirstFocusable();
+ if (newFirstControl === this.firstControl_) {
+ return;
+ }
+
+ if (this.firstControl_) {
+ this.unlisten(this.firstControl_, 'keydown', 'onFirstControlKeydown_');
+ }
+ this.firstControl_ = newFirstControl;
+ if (this.firstControl_) {
+ this.listen(
+ /** @type {!Element} */ (this.firstControl_), 'keydown',
+ 'onFirstControlKeydown_');
+ }
+ },
+
+ /** @private */
+ removeObservers_: function() {
+ if (this.firstControl_) {
+ this.unlisten(this.firstControl_, 'keydown', 'onFirstControlKeydown_');
+ }
+ if (this.controlObservers_.length > 0) {
+ this.controlObservers_.forEach(observer => {
+ observer.disconnect();
+ });
+ }
+ this.controlObservers_ = [];
+ },
+
+ /** @private */
+ addItems_: function() {
+ if (this.row_) {
+ this.removeObservers_();
+ this.row_.destroy();
+
+ const controls = this.root.querySelectorAll('[focus-row-control]');
+
+ controls.forEach(control => {
+ this.row_.addItem(
+ control.getAttribute('focus-type'),
+ /** @type {!HTMLElement} */
+ (cr.ui.FocusRow.getFocusableElement(control)));
+ this.addMutationObservers_(assert(control));
+ });
+ this.updateFirstControl_();
+ }
+ },
+
+ /**
+ * @return {!MutationObserver}
+ * @private
+ */
+ createObserver_: function() {
+ return new MutationObserver(mutations => {
+ const mutation = mutations[0];
+ if (mutation.attributeName === 'style' && mutation.oldValue) {
+ const newStyle = window.getComputedStyle(
+ /** @type {!Element} */ (mutation.target));
+ const oldDisplayValue = mutation.oldValue.match(/^display:(.*)(?=;)/);
+ const oldVisibilityValue =
+ mutation.oldValue.match(/^visibility:(.*)(?=;)/);
+ // Return early if display and visibility have not changed.
+ if (oldDisplayValue &&
+ newStyle.display === oldDisplayValue[1].trim() &&
+ oldVisibilityValue &&
+ newStyle.visibility === oldVisibilityValue[1].trim()) {
+ return;
+ }
+ }
+ this.updateFirstControl_();
+ });
+ },
+
+ /**
+ * The first focusable control changes if hidden, disabled, or style.display
+ * changes for the control or any of its ancestors. Add mutation observers
+ * to watch for these changes in order to ensure the first control keydown
+ * listener is always on the correct element.
+ * @param {!Element} control
+ * @private
+ */
+ addMutationObservers_: function(control) {
+ let current = control;
+ while (current && current != this.root) {
+ const currentObserver = this.createObserver_();
+ currentObserver.observe(current, {
+ attributes: true,
+ attributeFilter: ['hidden', 'disabled', 'style'],
+ attributeOldValue: true,
+ });
+ this.controlObservers_.push(currentObserver);
+ current = current.parentNode;
+ }
+ },
+
+ /**
+ * This function gets called when the row itself receives the focus event.
+ * @param {!Event} e The focus event
+ * @private
+ */
+ onFocus_: function(e) {
+ if (this.mouseFocused_) {
+ this.mouseFocused_ = false; // Consume and reset flag.
+ return;
+ }
+
+ // If focus is being restored from outside the item and the event is fired
+ // by the list item itself, focus the first control so that the user can
+ // tab through all the controls. When the user shift-tabs back to the row,
+ // or focus is restored to the row from a dropdown on the last item, the
+ // last child item will be focused before the row itself. Since this is
+ // the desired behavior, do not shift focus to the first item in these
+ // cases.
+ const restoreFocusToFirst =
+ this.listBlurred && e.composedPath()[0] === this;
+
+ if (this.lastFocused && !restoreFocusToFirst) {
+ this.row_.getEquivalentElement(this.lastFocused).focus();
+ } else {
+ const firstFocusable = assert(this.firstControl_);
+ firstFocusable.focus();
+ }
+ this.listBlurred = false;
+ },
+
+ /** @param {!KeyboardEvent} e */
+ onFirstControlKeydown_: function(e) {
+ if (e.shiftKey && e.key === 'Tab') {
+ this.focus();
+ }
+ },
+
+ /** @private */
+ ironListTabIndexChanged_: function() {
+ if (this.row_) {
+ this.row_.makeActive(this.ironListTabIndex == 0);
+ }
+
+ // If a new row is being focused, reset listBlurred. This means an item
+ // has been removed and iron-list is about to focus the next item.
+ if (this.ironListTabIndex == 0) {
+ this.listBlurred = false;
+ }
+ },
+
+ /** @private */
+ onMouseDown_: function() {
+ this.mouseFocused_ = true; // Set flag to not do any control-focusing.
+ },
+
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onBlur_: function(e) {
+ this.mouseFocused_ = false; // Reset flag since it's not active anymore.
+
+ const node =
+ e.relatedTarget ? /** @type {!Node} */ (e.relatedTarget) : null;
+ if (!this.parentNode.contains(node)) {
+ this.listBlurred = true;
+ }
+ },
+ };
+
+ return {
+ FocusRowBehaviorDelegate,
+ VirtualFocusRow,
+ FocusRowBehavior,
+ };
+});
diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js b/chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js
index ed5c00fe547..f2cb441ff30 100644
--- a/chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js
@@ -3,10 +3,11 @@
// found in the LICENSE file.
cr.define('cr.ui', function() {
- if (cr.ui.focusWithoutInk)
+ if (cr.ui.focusWithoutInk) {
return;
+ }
- var hideInk = false;
+ let hideInk = false;
assert(!cr.isIOS, 'pointerdown doesn\'t work on iOS');
@@ -25,8 +26,8 @@ cr.define('cr.ui', function() {
* helpful to show focus ripples in that case. This is Polymer-specific.
* @param {!Element} toFocus
*/
- var focusWithoutInk = function(toFocus) {
- var innerButton = null;
+ const focusWithoutInk = function(toFocus) {
+ let innerButton = null;
if (toFocus.parentElement &&
toFocus.parentElement.tagName == 'PAPER-ICON-BUTTON-LIGHT') {
@@ -44,7 +45,7 @@ cr.define('cr.ui', function() {
// Make sure the element is in the document we're listening to events on.
assert(document == toFocus.ownerDocument);
- var origNoInk;
+ let origNoInk;
if (hideInk) {
origNoInk = toFocus.noink;
@@ -53,13 +54,15 @@ cr.define('cr.ui', function() {
// For paper-icon-button-light elements, focus() needs to be called on the
// inner native <button> for it to work.
- if (innerButton)
+ if (innerButton) {
innerButton.focus();
- else
+ } else {
toFocus.focus();
+ }
- if (hideInk)
+ if (hideInk) {
toFocus.noink = origNoInk;
+ }
};
return {focusWithoutInk: focusWithoutInk};
diff --git a/chromium/ui/webui/resources/js/cr/ui/grid.js b/chromium/ui/webui/resources/js/cr/ui/grid.js
index dc17e3c3f1c..ab5676f3e36 100644
--- a/chromium/ui/webui/resources/js/cr/ui/grid.js
+++ b/chromium/ui/webui/resources/js/cr/ui/grid.js
@@ -13,9 +13,9 @@
*/
cr.define('cr.ui', function() {
- /** @const */ var ListSelectionController = cr.ui.ListSelectionController;
- /** @const */ var List = cr.ui.List;
- /** @const */ var ListItem = cr.ui.ListItem;
+ /** @const */ const ListSelectionController = cr.ui.ListSelectionController;
+ /** @const */ const List = cr.ui.List;
+ /** @const */ const ListItem = cr.ui.ListItem;
/**
* Creates a new grid item element.
@@ -24,7 +24,7 @@ cr.define('cr.ui', function() {
* @extends {cr.ui.ListItem}
*/
function GridItem(dataItem) {
- var el = cr.doc.createElement('li');
+ const el = cr.doc.createElement('li');
el.dataItem = dataItem;
el.__proto__ = GridItem.prototype;
return el;
@@ -48,7 +48,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {cr.ui.List}
*/
- var Grid = cr.ui.define('grid');
+ const Grid = cr.ui.define('grid');
Grid.prototype = {
__proto__: List.prototype,
@@ -77,8 +77,9 @@ cr.define('cr.ui', function() {
return true;
},
set fixedHeight(fixedHeight) {
- if (!fixedHeight)
+ if (!fixedHeight) {
console.warn('cr.ui.Grid does not support fixedHeight = false');
+ }
},
/**
@@ -88,31 +89,35 @@ cr.define('cr.ui', function() {
*/
getColumnCount_: function() {
// Size comes here with margin already collapsed.
- var size = this.getDefaultItemSize_();
+ const size = this.getDefaultItemSize_();
- if (!size)
+ if (!size) {
return 0;
+ }
// We should uncollapse margin, since margin isn't collapsed for
// inline-block elements according to css spec which are thumbnail items.
- var width = size.width + Math.min(size.marginLeft, size.marginRight);
- var height = size.height + Math.min(size.marginTop, size.marginBottom);
+ const width = size.width + Math.min(size.marginLeft, size.marginRight);
+ const height = size.height + Math.min(size.marginTop, size.marginBottom);
- if (!width || !height)
+ if (!width || !height) {
return 0;
+ }
- var itemCount = this.dataModel ? this.dataModel.length : 0;
- if (!itemCount)
+ const itemCount = this.dataModel ? this.dataModel.length : 0;
+ if (!itemCount) {
return 0;
+ }
- var columns = Math.floor(
+ const columns = Math.floor(
(this.clientWidthWithoutScrollbar_ - this.horizontalPadding_) /
width);
- if (!columns)
+ if (!columns) {
return 0;
+ }
- var rows = Math.ceil(itemCount / columns);
+ const rows = Math.ceil(itemCount / columns);
if (rows * height <= this.clientHeight_) {
// Content fits within the client area (no scrollbar required).
return columns;
@@ -130,11 +135,11 @@ cr.define('cr.ui', function() {
*/
updateMetrics_: function() {
// Check changings that may affect number of columns.
- var offsetWidth = this.offsetWidth;
- var offsetHeight = this.offsetHeight;
- var style = window.getComputedStyle(this);
- var overflowY = style.overflowY;
- var horizontalPadding =
+ const offsetWidth = this.offsetWidth;
+ const offsetHeight = this.offsetHeight;
+ const style = window.getComputedStyle(this);
+ const overflowY = style.overflowY;
+ const horizontalPadding =
parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
if (this.lastOffsetWidth_ == offsetWidth &&
@@ -152,7 +157,7 @@ cr.define('cr.ui', function() {
if (overflowY == 'auto' && offsetWidth > 0) {
// Column number may depend on whether scrollbar is present or not.
- var originalClientWidth = this.clientWidth;
+ const originalClientWidth = this.clientWidth;
// At first make sure there is no scrollbar and calculate clientWidth
// (triggers reflow).
this.style.overflowY = 'hidden';
@@ -241,11 +246,11 @@ cr.define('cr.ui', function() {
* @override
*/
getItemsInViewPort: function(scrollTop, clientHeight) {
- var itemHeight = this.getDefaultItemHeight_();
- var firstIndex =
+ const itemHeight = this.getDefaultItemHeight_();
+ const firstIndex =
this.autoExpands ? 0 : this.getIndexForListOffset_(scrollTop);
- var columns = this.columns;
- var count = this.autoExpands ?
+ const columns = this.columns;
+ let count = this.autoExpands ?
this.dataModel.length :
Math.max(
columns * (Math.ceil(clientHeight / itemHeight) + 1),
@@ -265,19 +270,19 @@ cr.define('cr.ui', function() {
mergeItems: function(firstIndex, lastIndex) {
List.prototype.mergeItems.call(this, firstIndex, lastIndex);
- var afterFiller = this.afterFiller_;
- var columns = this.columns;
+ const afterFiller = this.afterFiller_;
+ const columns = this.columns;
- for (var item = this.beforeFiller_.nextSibling; item != afterFiller;) {
- var next = item.nextSibling;
+ for (let item = this.beforeFiller_.nextSibling; item != afterFiller;) {
+ const next = item.nextSibling;
if (isSpacer(item)) {
// Spacer found on a place it mustn't be.
this.removeChild(item);
item = next;
continue;
}
- var index = item.listIndex;
- var nextIndex = index + 1;
+ const index = item.listIndex;
+ const nextIndex = index + 1;
// Invisible pinned item could be outside of the
// [firstIndex, lastIndex). Ignore it.
@@ -288,13 +293,14 @@ cr.define('cr.ui', function() {
item = next.nextSibling;
} else {
// Insert spacer.
- var spacer = this.ownerDocument.createElement('div');
+ const spacer = this.ownerDocument.createElement('div');
spacer.className = 'spacer';
this.insertBefore(spacer, next);
item = next;
}
- } else
+ } else {
item = next;
+ }
}
function isSpacer(child) {
@@ -310,11 +316,11 @@ cr.define('cr.ui', function() {
* @override
*/
getAfterFillerHeight: function(lastIndex) {
- var columns = this.columns;
- var itemHeight = this.getDefaultItemHeight_();
+ const columns = this.columns;
+ const itemHeight = this.getDefaultItemHeight_();
// We calculate the row of last item, and the row of last shown item.
// The difference is the number of rows not shown.
- var afterRows = Math.floor((this.dataModel.length - 1) / columns) -
+ const afterRows = Math.floor((this.dataModel.length - 1) / columns) -
Math.floor((lastIndex - 1) / columns);
return afterRows * itemHeight;
},
@@ -332,7 +338,7 @@ cr.define('cr.ui', function() {
redraw: function() {
this.updateMetrics_();
- var itemCount = this.dataModel ? this.dataModel.length : 0;
+ const itemCount = this.dataModel ? this.dataModel.length : 0;
if (this.lastItemCount_ != itemCount) {
this.lastItemCount_ = itemCount;
// Force recalculation.
@@ -380,11 +386,13 @@ cr.define('cr.ui', function() {
* @override
*/
getIndexBelow: function(index) {
- if (this.isAccessibilityEnabled())
+ if (this.isAccessibilityEnabled()) {
return this.getIndexAfter(index);
- var last = this.getLastIndex();
- if (index == last)
+ }
+ const last = this.getLastIndex();
+ if (index == last) {
return -1;
+ }
index += this.grid_.columns;
return Math.min(index, last);
},
@@ -396,10 +404,12 @@ cr.define('cr.ui', function() {
* @override
*/
getIndexAbove: function(index) {
- if (this.isAccessibilityEnabled())
+ if (this.isAccessibilityEnabled()) {
return this.getIndexBefore(index);
- if (index == 0)
+ }
+ if (index == 0) {
return -1;
+ }
index -= this.grid_.columns;
return Math.max(index, 0);
},
diff --git a/chromium/ui/webui/resources/js/cr/ui/list.js b/chromium/ui/webui/resources/js/cr/ui/list.js
index f370f0f56f7..06e1f03e783 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list.js
@@ -26,9 +26,9 @@ cr.ui.Size;
*/
cr.define('cr.ui', function() {
- /** @const */ var ListSelectionModel = cr.ui.ListSelectionModel;
- /** @const */ var ListSelectionController = cr.ui.ListSelectionController;
- /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
+ /** @const */ const ListSelectionModel = cr.ui.ListSelectionModel;
+ /** @const */ const ListSelectionController = cr.ui.ListSelectionController;
+ /** @const */ const ArrayDataModel = cr.ui.ArrayDataModel;
/**
* Whether a mouse event is inside the element viewport. This will return
@@ -38,9 +38,9 @@ cr.define('cr.ui', function() {
* @return {boolean} Whether the mouse event was inside the viewport.
*/
function inViewport(el, e) {
- var rect = el.getBoundingClientRect();
- var x = e.clientX;
- var y = e.clientY;
+ const rect = el.getBoundingClientRect();
+ const x = e.clientX;
+ const y = e.clientY;
return x >= rect.left + el.clientLeft &&
x < rect.left + el.clientLeft + el.clientWidth &&
y >= rect.top + el.clientTop &&
@@ -57,7 +57,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLUListElement}
*/
- var List = cr.ui.define('list');
+ const List = cr.ui.define('list');
List.prototype = {
__proto__: HTMLUListElement.prototype,
@@ -125,8 +125,9 @@ cr.define('cr.ui', function() {
* @type {ArrayDataModel}
*/
set dataModel(dataModel) {
- if (this.dataModel_ == dataModel)
+ if (this.dataModel_ == dataModel) {
return;
+ }
if (!this.boundHandleDataModelPermuted_) {
this.boundHandleDataModelPermuted_ =
@@ -147,8 +148,9 @@ cr.define('cr.ui', function() {
this.cachedItems_ = {};
this.cachedItemHeights_ = {};
this.selectionModel.clear();
- if (dataModel)
+ if (dataModel) {
this.selectionModel.adjustLength(dataModel.length);
+ }
if (this.dataModel_) {
this.dataModel_.addEventListener(
@@ -185,9 +187,10 @@ cr.define('cr.ui', function() {
return this.selectionModel_;
},
set selectionModel(sm) {
- var oldSm = this.selectionModel_;
- if (oldSm == sm)
+ const oldSm = this.selectionModel_;
+ if (oldSm == sm) {
return;
+ }
if (!this.boundHandleOnChange_) {
this.boundHandleOnChange_ = this.handleOnChange_.bind(this);
@@ -217,8 +220,9 @@ cr.define('cr.ui', function() {
return this.autoExpands_;
},
set autoExpands(autoExpands) {
- if (this.autoExpands_ == autoExpands)
+ if (this.autoExpands_ == autoExpands) {
return;
+ }
this.autoExpands_ = autoExpands;
this.redraw();
},
@@ -231,8 +235,9 @@ cr.define('cr.ui', function() {
return this.fixedHeight_;
},
set fixedHeight(fixedHeight) {
- if (this.fixedHeight_ == fixedHeight)
+ if (this.fixedHeight_ == fixedHeight) {
return;
+ }
this.fixedHeight_ = fixedHeight;
this.redraw();
},
@@ -242,18 +247,19 @@ cr.define('cr.ui', function() {
* @type {*}
*/
get selectedItem() {
- var dataModel = this.dataModel;
+ const dataModel = this.dataModel;
if (dataModel) {
- var index = this.selectionModel.selectedIndex;
- if (index != -1)
+ const index = this.selectionModel.selectedIndex;
+ if (index != -1) {
return dataModel.item(index);
+ }
}
return null;
},
set selectedItem(selectedItem) {
- var dataModel = this.dataModel;
+ const dataModel = this.dataModel;
if (dataModel) {
- var index = this.dataModel.indexOf(selectedItem);
+ const index = this.dataModel.indexOf(selectedItem);
this.selectionModel.selectedIndex = index;
}
},
@@ -263,8 +269,8 @@ cr.define('cr.ui', function() {
* @type {!Array<*>}
*/
get selectedItems() {
- var indexes = this.selectionModel.selectedIndexes;
- var dataModel = this.dataModel;
+ const indexes = this.selectionModel.selectedIndexes;
+ const dataModel = this.dataModel;
if (dataModel) {
return indexes.map(function(i) {
return dataModel.item(i);
@@ -309,8 +315,9 @@ cr.define('cr.ui', function() {
*/
endBatchUpdates: function() {
this.batchCount_--;
- if (this.batchCount_ == 0)
+ if (this.batchCount_ == 0) {
this.redraw();
+ }
},
/**
@@ -326,7 +333,7 @@ cr.define('cr.ui', function() {
this.appendChild(this.beforeFiller_);
this.appendChild(this.afterFiller_);
- var length = this.dataModel ? this.dataModel.length : 0;
+ const length = this.dataModel ? this.dataModel.length : 0;
this.selectionModel = new ListSelectionModel(length);
this.addEventListener('dblclick', this.handleDoubleClick_);
@@ -344,8 +351,9 @@ cr.define('cr.ui', function() {
this.setAttribute('role', 'list');
// Make list focusable
- if (!this.hasAttribute('tabindex'))
+ if (!this.hasAttribute('tabindex')) {
this.tabIndex = 0;
+ }
},
/**
@@ -372,15 +380,17 @@ cr.define('cr.ui', function() {
*/
getItemHeightByIndex_: function(index) {
// If |this.fixedHeight_| is true, all the rows have same default height.
- if (this.fixedHeight_)
+ if (this.fixedHeight_) {
return this.getDefaultItemHeight_();
+ }
- if (this.cachedItemHeights_[index])
+ if (this.cachedItemHeights_[index]) {
return this.cachedItemHeights_[index];
+ }
- var item = this.getListItemByIndex(index);
+ const item = this.getListItemByIndex(index);
if (item) {
- var h = this.measureItemHeight_(item);
+ const h = this.measureItemHeight_(item);
this.cachedItemHeights_[index] = h;
return h;
}
@@ -409,7 +419,7 @@ cr.define('cr.ui', function() {
* into account, and the top, bottom, left and right margins themselves.
*/
measureItem: function(opt_item) {
- var dataModel = this.dataModel;
+ const dataModel = this.dataModel;
if (!dataModel || !dataModel.length) {
return {
height: 0,
@@ -420,23 +430,23 @@ cr.define('cr.ui', function() {
marginRight: 0
};
}
- var item = opt_item || this.cachedMeasuredItem_ ||
+ const item = opt_item || this.cachedMeasuredItem_ ||
this.createItem(dataModel.item(0));
if (!opt_item) {
this.cachedMeasuredItem_ = item;
this.appendChild(item);
}
- var rect = item.getBoundingClientRect();
- var cs = getComputedStyle(item);
- var mt = parseFloat(cs.marginTop);
- var mb = parseFloat(cs.marginBottom);
- var ml = parseFloat(cs.marginLeft);
- var mr = parseFloat(cs.marginRight);
- var h = rect.height;
- var w = rect.width;
- var mh = 0;
- var mv = 0;
+ const rect = item.getBoundingClientRect();
+ const cs = getComputedStyle(item);
+ const mt = parseFloat(cs.marginTop);
+ const mb = parseFloat(cs.marginBottom);
+ const ml = parseFloat(cs.marginLeft);
+ const mr = parseFloat(cs.marginRight);
+ let h = rect.height;
+ let w = rect.width;
+ let mh = 0;
+ let mv = 0;
// Handle margin collapsing.
if (mt < 0 && mb < 0) {
@@ -457,8 +467,9 @@ cr.define('cr.ui', function() {
}
w += mh;
- if (!opt_item)
+ if (!opt_item) {
this.removeChild(item);
+ }
return {
height: Math.max(0, h),
marginTop: mt,
@@ -475,22 +486,24 @@ cr.define('cr.ui', function() {
* @private
*/
handleDoubleClick_: function(e) {
- if (this.disabled)
+ if (this.disabled) {
return;
+ }
- var target = /** @type {HTMLElement} */ (e.target);
+ const target = /** @type {HTMLElement} */ (e.target);
- var ancestor = this.getListItemAncestor(target);
- var index = -1;
+ const ancestor = this.getListItemAncestor(target);
+ let index = -1;
if (ancestor) {
index = this.getIndexOfListItem(ancestor);
this.activateItemAtIndex(index);
}
- var sm = this.selectionModel;
- var indexSelected = sm.getIndexSelected(index);
- if (!indexSelected)
+ const sm = this.selectionModel;
+ const indexSelected = sm.getIndexSelected(index);
+ if (!indexSelected) {
this.handlePointerDownUp_(e);
+ }
},
/**
@@ -499,22 +512,24 @@ cr.define('cr.ui', function() {
* @private
*/
handlePointerDownUp_: function(e) {
- if (this.disabled)
+ if (this.disabled) {
return;
+ }
- var target = /** @type {HTMLElement} */ (e.target);
+ let target = /** @type {HTMLElement} */ (e.target);
// If the target was this element we need to make sure that the user did
// not click on a border or a scrollbar.
if (target == this) {
- if (inViewport(target, e))
+ if (inViewport(target, e)) {
this.selectionController_.handlePointerDownUp(e, -1);
+ }
return;
}
target = this.getListItemAncestor(target);
- var index = this.getIndexOfListItem(target);
+ const index = this.getIndexOfListItem(target);
this.selectionController_.handlePointerDownUp(e, index);
},
@@ -525,8 +540,9 @@ cr.define('cr.ui', function() {
* @private
*/
handleElementFocus_: function(e) {
- if (!this.hasElementFocus)
+ if (!this.hasElementFocus) {
this.hasElementFocus = true;
+ }
},
/**
@@ -540,8 +556,9 @@ cr.define('cr.ui', function() {
* Node.prototype.contains() will be fixed.
*/
handleElementBlur_: function(e) {
- if (!this.contains(e.relatedTarget))
+ if (!this.contains(e.relatedTarget)) {
this.hasElementFocus = false;
+ }
},
/**
@@ -551,7 +568,7 @@ cr.define('cr.ui', function() {
* @return {HTMLLIElement} The list item containing |element|, or null.
*/
getListItemAncestor: function(element) {
- var container = element;
+ let container = element;
while (container && container.parentNode != this) {
container = container.parentNode;
}
@@ -563,8 +580,9 @@ cr.define('cr.ui', function() {
* @param {Event} e The keydown event.
*/
handleKeyDown: function(e) {
- if (!this.disabled)
+ if (!this.disabled) {
this.selectionController_.handleKeyDown(e);
+ }
},
/**
@@ -581,10 +599,11 @@ cr.define('cr.ui', function() {
* @private
*/
handleTouchEvents_: function(e) {
- if (this.disabled)
+ if (this.disabled) {
return;
+ }
- var target = /** @type {HTMLElement} */ (e.target);
+ let target = /** @type {HTMLElement} */ (e.target);
if (target == this) {
// Unlike the mouse events, we don't check if the touch is inside the
@@ -598,7 +617,7 @@ cr.define('cr.ui', function() {
target = this.getListItemAncestor(target);
- var index = this.getIndexOfListItem(target);
+ const index = this.getIndexOfListItem(target);
this.selectionController_.handleTouchEvents(e, index);
},
@@ -610,7 +629,7 @@ cr.define('cr.ui', function() {
*/
handleOnChange_: function(ce) {
ce.changes.forEach(function(change) {
- var listItem = this.getListItemByIndex(change.index);
+ const listItem = this.getListItemByIndex(change.index);
if (listItem) {
listItem.selected = change.selected;
if (change.selected) {
@@ -633,15 +652,17 @@ cr.define('cr.ui', function() {
* @protected
*/
handleLeadChange: function(e) {
- var element;
+ let element;
if (e.oldValue != -1) {
- if ((element = this.getListItemByIndex(e.oldValue)))
+ if ((element = this.getListItemByIndex(e.oldValue))) {
element.lead = false;
+ }
}
if (e.newValue != -1) {
- if ((element = this.getListItemByIndex(e.newValue)))
+ if ((element = this.getListItemByIndex(e.newValue))) {
element.lead = true;
+ }
if (e.oldValue != e.newValue) {
this.scrollIndexIntoView(e.newValue);
// If the lead item has a different height than other items, then we
@@ -654,7 +675,7 @@ cr.define('cr.ui', function() {
// the bottom of the list is not "sticky.") So, we set a timeout to
// rescroll the list after this all gets sorted out. This is perhaps
// not the most elegant solution, but no others seem obvious.
- var self = this;
+ const self = this;
window.setTimeout(function() {
self.scrollIndexIntoView(e.newValue);
}, 0);
@@ -676,10 +697,10 @@ cr.define('cr.ui', function() {
* @param {Event} e The 'permuted' event.
*/
handleDataModelPermuted_: function(e) {
- var newCachedItems = {};
- for (var index in this.cachedItems_) {
+ const newCachedItems = {};
+ for (const index in this.cachedItems_) {
if (e.permutation[index] != -1) {
- var newIndex = e.permutation[index];
+ const newIndex = e.permutation[index];
newCachedItems[newIndex] = this.cachedItems_[index];
newCachedItems[newIndex].listIndex = newIndex;
}
@@ -687,8 +708,8 @@ cr.define('cr.ui', function() {
this.cachedItems_ = newCachedItems;
this.pinnedItem_ = null;
- var newCachedItemHeights = {};
- for (var index in this.cachedItemHeights_) {
+ const newCachedItemHeights = {};
+ for (const index in this.cachedItemHeights_) {
if (e.permutation[index] != -1) {
newCachedItemHeights[e.permutation[index]] =
this.cachedItemHeights_[index];
@@ -698,7 +719,7 @@ cr.define('cr.ui', function() {
this.startBatchUpdates();
- var sm = this.selectionModel;
+ const sm = this.selectionModel;
sm.adjustLength(e.newLength);
sm.adjustToReordering(e.permutation);
@@ -722,12 +743,12 @@ cr.define('cr.ui', function() {
*/
getItemTop: function(index) {
if (this.fixedHeight_) {
- var itemHeight = this.getDefaultItemHeight_();
+ const itemHeight = this.getDefaultItemHeight_();
return index * itemHeight;
} else {
this.ensureAllItemSizesInCache();
- var top = 0;
- for (var i = 0; i < index; i++) {
+ let top = 0;
+ for (let i = 0; i < index; i++) {
top += this.getItemHeightByIndex_(i);
}
return top;
@@ -756,21 +777,22 @@ cr.define('cr.ui', function() {
* @param {number} index The index of the item to scroll into view.
*/
scrollIndexIntoView: function(index) {
- var dataModel = this.dataModel;
- if (!dataModel || index < 0 || index >= dataModel.length)
+ const dataModel = this.dataModel;
+ if (!dataModel || index < 0 || index >= dataModel.length) {
return;
+ }
- var itemHeight = this.getItemHeightByIndex_(index);
- var scrollTop = this.scrollTop;
- var top = this.getItemTop(index);
- var clientHeight = this.clientHeight;
+ const itemHeight = this.getItemHeightByIndex_(index);
+ const scrollTop = this.scrollTop;
+ const top = this.getItemTop(index);
+ const clientHeight = this.clientHeight;
- var cs = getComputedStyle(this);
- var paddingY =
+ const cs = getComputedStyle(this);
+ const paddingY =
parseInt(cs.paddingTop, 10) + parseInt(cs.paddingBottom, 10);
- var availableHeight = clientHeight - paddingY;
+ const availableHeight = clientHeight - paddingY;
- var self = this;
+ const self = this;
// Function to adjust the tops of viewport and row.
function scrollToAdjustTop() {
self.scrollTop = top;
@@ -782,15 +804,17 @@ cr.define('cr.ui', function() {
// Check if the entire of given indexed row can be shown in the viewport.
if (itemHeight <= availableHeight) {
- if (top < scrollTop)
+ if (top < scrollTop) {
scrollToAdjustTop();
- else if (scrollTop + availableHeight < top + itemHeight)
+ } else if (scrollTop + availableHeight < top + itemHeight) {
scrollToAdjustBottom();
+ }
} else {
- if (scrollTop < top)
+ if (scrollTop < top) {
scrollToAdjustTop();
- else if (top + itemHeight < scrollTop + availableHeight)
+ } else if (top + itemHeight < scrollTop + availableHeight) {
scrollToAdjustBottom();
+ }
}
},
@@ -800,10 +824,11 @@ cr.define('cr.ui', function() {
getRectForContextMenu: function() {
// TODO(arv): Add trait support so we can share more code between trees
// and lists.
- var index = this.selectionModel.selectedIndex;
- var el = this.getListItemByIndex(index);
- if (el)
+ const index = this.selectionModel.selectedIndex;
+ const el = this.getListItemByIndex(index);
+ if (el) {
return el.getBoundingClientRect();
+ }
return this.getBoundingClientRect();
},
@@ -814,9 +839,9 @@ cr.define('cr.ui', function() {
* @return {cr.ui.ListItem} The first found list item or null if not found.
*/
getListItem: function(value) {
- var dataModel = this.dataModel;
+ const dataModel = this.dataModel;
if (dataModel) {
- var index = dataModel.indexOf(value);
+ const index = dataModel.indexOf(value);
return this.getListItemByIndex(index);
}
return null;
@@ -837,7 +862,7 @@ cr.define('cr.ui', function() {
* @return {number} The index of the list item, or -1 if not found.
*/
getIndexOfListItem: function(item) {
- var index = item.listIndex;
+ const index = item.listIndex;
if (this.cachedItems_[index] == item) {
return index;
}
@@ -850,10 +875,11 @@ cr.define('cr.ui', function() {
* @return {!cr.ui.ListItem} The newly created list item.
*/
createItem: function(value) {
- var item = new this.itemConstructor_(value);
+ const item = new this.itemConstructor_(value);
item.label = value;
- if (typeof item.decorate == 'function')
+ if (typeof item.decorate == 'function') {
item.decorate();
+ }
return item;
},
@@ -875,8 +901,8 @@ cr.define('cr.ui', function() {
* @return {{top: number, height: number}} The heights for the given index.
*/
getHeightsForIndex: function(index) {
- var itemHeight = this.getItemHeightByIndex_(index);
- var top = this.getItemTop(index);
+ const itemHeight = this.getItemHeightByIndex_(index);
+ const top = this.getItemTop(index);
return {top: top, height: itemHeight};
},
@@ -890,35 +916,39 @@ cr.define('cr.ui', function() {
* @protected
*/
getIndexForListOffset_: function(offset) {
- var itemHeight = this.getDefaultItemHeight_();
- if (!itemHeight)
+ const itemHeight = this.getDefaultItemHeight_();
+ if (!itemHeight) {
return this.dataModel.length;
+ }
- if (this.fixedHeight_)
+ if (this.fixedHeight_) {
return this.getFirstItemInRow(Math.floor(offset / itemHeight));
+ }
// If offset exceeds the height of list.
- var lastHeight = 0;
+ let lastHeight = 0;
if (this.dataModel.length) {
- var h = this.getHeightsForIndex(this.dataModel.length - 1);
+ const h = this.getHeightsForIndex(this.dataModel.length - 1);
lastHeight = h.top + h.height;
}
- if (lastHeight < offset)
+ if (lastHeight < offset) {
return this.dataModel.length;
+ }
// Estimates index.
- var estimatedIndex =
+ let estimatedIndex =
Math.min(Math.floor(offset / itemHeight), this.dataModel.length - 1);
- var isIncrementing = this.getItemTop(estimatedIndex) < offset;
+ const isIncrementing = this.getItemTop(estimatedIndex) < offset;
// Searchs the correct index.
do {
- var heights = this.getHeightsForIndex(estimatedIndex);
- var top = heights.top;
- var height = heights.height;
+ const heights = this.getHeightsForIndex(estimatedIndex);
+ const top = heights.top;
+ const height = heights.height;
- if (top <= offset && offset <= (top + height))
+ if (top <= offset && offset <= (top + height)) {
break;
+ }
isIncrementing ? ++estimatedIndex : --estimatedIndex;
} while (0 < estimatedIndex && estimatedIndex < this.dataModel.length);
@@ -935,7 +965,7 @@ cr.define('cr.ui', function() {
* @protected
*/
countItemsInRange_: function(startIndex, endOffset) {
- var endIndex = this.getIndexForListOffset_(endOffset);
+ const endIndex = this.getIndexForListOffset_(endOffset);
return endIndex - startIndex + 1;
},
@@ -954,8 +984,8 @@ cr.define('cr.ui', function() {
last: this.dataModel.length
};
} else {
- var firstIndex = this.getIndexForListOffset_(scrollTop);
- var lastIndex = this.getIndexForListOffset_(scrollTop + clientHeight);
+ const firstIndex = this.getIndexForListOffset_(scrollTop);
+ const lastIndex = this.getIndexForListOffset_(scrollTop + clientHeight);
return {
first: firstIndex,
@@ -974,13 +1004,13 @@ cr.define('cr.ui', function() {
* @param {number} lastIndex The index of last item, exclusively.
*/
mergeItems: function(firstIndex, lastIndex) {
- var self = this;
- var dataModel = this.dataModel;
- var currentIndex = firstIndex;
+ const self = this;
+ const dataModel = this.dataModel;
+ let currentIndex = firstIndex;
function insert() {
- var dataItem = dataModel.item(currentIndex);
- var newItem =
+ const dataItem = dataModel.item(currentIndex);
+ const newItem =
self.cachedItems_[currentIndex] || self.createItem(dataItem);
newItem.listIndex = currentIndex;
self.cachedItems_[currentIndex] = newItem;
@@ -989,20 +1019,22 @@ cr.define('cr.ui', function() {
}
function remove() {
- var next = item.nextSibling;
- if (item != self.pinnedItem_)
+ const next = item.nextSibling;
+ if (item != self.pinnedItem_) {
self.removeChild(item);
+ }
item = next;
}
- for (var item = this.beforeFiller_.nextSibling;
+ let item;
+ for (item = this.beforeFiller_.nextSibling;
item != this.afterFiller_ && currentIndex < lastIndex;) {
if (!this.isItem(item)) {
item = item.nextSibling;
continue;
}
- var index = item.listIndex;
+ const index = item.listIndex;
if (this.cachedItems_[index] != item || index < currentIndex) {
remove();
} else if (index == currentIndex) {
@@ -1015,43 +1047,46 @@ cr.define('cr.ui', function() {
}
while (item != this.afterFiller_) {
- if (this.isItem(item))
+ if (this.isItem(item)) {
remove();
- else
+ } else {
item = item.nextSibling;
+ }
}
if (this.pinnedItem_) {
- var index = this.pinnedItem_.listIndex;
+ const index = this.pinnedItem_.listIndex;
this.pinnedItem_.hidden = index < firstIndex || index >= lastIndex;
this.cachedItems_[index] = this.pinnedItem_;
- if (index >= lastIndex)
- item = this.pinnedItem_; // Insert new items before this one.
+ if (index >= lastIndex) {
+ item = this.pinnedItem_;
+ } // Insert new items before this one.
}
- while (currentIndex < lastIndex)
+ while (currentIndex < lastIndex) {
insert();
+ }
},
/**
* Ensures that all the item sizes in the list have been already cached.
*/
ensureAllItemSizesInCache: function() {
- var measuringIndexes = [];
- var isElementAppended = [];
- for (var y = 0; y < this.dataModel.length; y++) {
+ const measuringIndexes = [];
+ const isElementAppended = [];
+ for (let y = 0; y < this.dataModel.length; y++) {
if (!this.cachedItemHeights_[y]) {
measuringIndexes.push(y);
isElementAppended.push(false);
}
}
- var measuringItems = [];
+ const measuringItems = [];
// Adds temporary elements.
- for (var y = 0; y < measuringIndexes.length; y++) {
- var index = measuringIndexes[y];
- var dataItem = this.dataModel.item(index);
- var listItem = this.cachedItems_[index] || this.createItem(dataItem);
+ for (let y = 0; y < measuringIndexes.length; y++) {
+ const index = measuringIndexes[y];
+ const dataItem = this.dataModel.item(index);
+ const listItem = this.cachedItems_[index] || this.createItem(dataItem);
listItem.listIndex = index;
// If |listItems| is not on the list, apppends it to the list and sets
@@ -1067,17 +1102,18 @@ cr.define('cr.ui', function() {
// All mesurings must be placed after adding all the elements, to prevent
// performance reducing.
- for (var y = 0; y < measuringIndexes.length; y++) {
- var index = measuringIndexes[y];
+ for (let y = 0; y < measuringIndexes.length; y++) {
+ const index = measuringIndexes[y];
this.cachedItemHeights_[index] =
this.measureItemHeight_(measuringItems[y]);
}
// Removes all the temprary elements.
- for (var y = 0; y < measuringIndexes.length; y++) {
+ for (let y = 0; y < measuringIndexes.length; y++) {
// If the list item has been appended above, removes it.
- if (isElementAppended[y])
+ if (isElementAppended[y]) {
this.removeChild(measuringItems[y]);
+ }
}
},
@@ -1088,13 +1124,14 @@ cr.define('cr.ui', function() {
*/
getAfterFillerHeight: function(lastIndex) {
if (this.fixedHeight_) {
- var itemHeight = this.getDefaultItemHeight_();
+ const itemHeight = this.getDefaultItemHeight_();
return (this.dataModel.length - lastIndex) * itemHeight;
}
- var height = 0;
- for (var i = lastIndex; i < this.dataModel.length; i++)
+ let height = 0;
+ for (let i = lastIndex; i < this.dataModel.length; i++) {
height += this.getItemHeightByIndex_(i);
+ }
return height;
},
@@ -1102,10 +1139,11 @@ cr.define('cr.ui', function() {
* Redraws the viewport.
*/
redraw: function() {
- if (this.batchCount_ != 0)
+ if (this.batchCount_ != 0) {
return;
+ }
- var dataModel = this.dataModel;
+ const dataModel = this.dataModel;
if (!dataModel || !this.autoExpands_ && this.clientHeight == 0) {
this.cachedItems_ = {};
this.firstIndex_ = 0;
@@ -1116,32 +1154,33 @@ cr.define('cr.ui', function() {
}
// Save the previous positions before any manipulation of elements.
- var scrollTop = this.scrollTop;
- var clientHeight = this.clientHeight;
+ const scrollTop = this.scrollTop;
+ const clientHeight = this.clientHeight;
// Store all the item sizes into the cache in advance, to prevent
// interleave measuring with mutating dom.
- if (!this.fixedHeight_)
+ if (!this.fixedHeight_) {
this.ensureAllItemSizesInCache();
+ }
- var autoExpands = this.autoExpands_;
+ const autoExpands = this.autoExpands_;
- var itemsInViewPort = this.getItemsInViewPort(scrollTop, clientHeight);
+ const itemsInViewPort = this.getItemsInViewPort(scrollTop, clientHeight);
// Draws the hidden rows just above/below the viewport to prevent
// flashing in scroll.
- var firstIndex = Math.max(
+ const firstIndex = Math.max(
0, Math.min(dataModel.length - 1, itemsInViewPort.first - 1));
- var lastIndex = Math.min(itemsInViewPort.last + 1, dataModel.length);
+ const lastIndex = Math.min(itemsInViewPort.last + 1, dataModel.length);
- var beforeFillerHeight =
+ const beforeFillerHeight =
this.autoExpands ? 0 : this.getItemTop(firstIndex);
- var afterFillerHeight =
+ const afterFillerHeight =
this.autoExpands ? 0 : this.getAfterFillerHeight(lastIndex);
this.beforeFiller_.style.height = beforeFillerHeight + 'px';
- var sm = this.selectionModel;
- var leadIndex = sm.leadIndex;
+ const sm = this.selectionModel;
+ const leadIndex = sm.leadIndex;
// If the pinned item is hidden and it is not the lead item, then remove
// it from cache. Note, that we restore the hidden status to false, since
@@ -1170,11 +1209,13 @@ cr.define('cr.ui', function() {
// We don't set the lead or selected properties until after adding all
// items, in case they force relayout in response to these events.
- if (leadIndex != -1 && this.cachedItems_[leadIndex])
+ if (leadIndex != -1 && this.cachedItems_[leadIndex]) {
this.cachedItems_[leadIndex].lead = true;
- for (var y = firstIndex; y < lastIndex; y++) {
- if (sm.getIndexSelected(y) != this.cachedItems_[y].selected)
+ }
+ for (let y = firstIndex; y < lastIndex; y++) {
+ if (sm.getIndexSelected(y) != this.cachedItems_[y].selected) {
this.cachedItems_[y].selected = !this.cachedItems_[y].selected;
+ }
}
this.firstIndex_ = firstIndex;
@@ -1185,7 +1226,7 @@ cr.define('cr.ui', function() {
// Mesurings must be placed after adding all the elements, to prevent
// performance reducing.
if (!this.fixedHeight_) {
- for (var y = firstIndex; y < lastIndex; y++) {
+ for (let y = firstIndex; y < lastIndex; y++) {
this.cachedItemHeights_[y] =
this.measureItemHeight_(this.cachedItems_[y]);
}
@@ -1248,12 +1289,13 @@ cr.define('cr.ui', function() {
* @return {cr.ui.ListItem} The lead item for the list.
*/
ensureLeadItemExists: function() {
- var index = this.selectionModel.leadIndex;
- if (index < 0)
+ const index = this.selectionModel.leadIndex;
+ if (index < 0) {
return null;
- var cachedItems = this.cachedItems_ || {};
+ }
+ const cachedItems = this.cachedItems_ || {};
- var item =
+ const item =
cachedItems[index] || this.createItem(this.dataModel.item(index));
if (this.pinnedItem_ != item && this.pinnedItem_ &&
this.pinnedItem_.hidden) {
@@ -1262,18 +1304,21 @@ cr.define('cr.ui', function() {
this.pinnedItem_ = item;
cachedItems[index] = item;
item.listIndex = index;
- if (item.parentNode == this)
+ if (item.parentNode == this) {
return item;
+ }
- if (this.batchCount_ != 0)
+ if (this.batchCount_ != 0) {
item.hidden = true;
+ }
// Item will get to the right place in redraw. Choose place to insert
// reducing items reinsertion.
- if (index <= this.firstIndex_)
+ if (index <= this.firstIndex_) {
this.insertBefore(item, this.beforeFiller_.nextSibling);
- else
+ } else {
this.insertBefore(item, this.afterFiller_);
+ }
this.redraw();
return item;
},
@@ -1284,23 +1329,23 @@ cr.define('cr.ui', function() {
*/
startDragSelection: function(event) {
event.preventDefault();
- var border = document.createElement('div');
+ const border = document.createElement('div');
border.className = 'drag-selection-border';
- var rect = this.getBoundingClientRect();
- var startX = event.clientX - rect.left + this.scrollLeft;
- var startY = event.clientY - rect.top + this.scrollTop;
+ const rect = this.getBoundingClientRect();
+ const startX = event.clientX - rect.left + this.scrollLeft;
+ const startY = event.clientY - rect.top + this.scrollTop;
border.style.left = startX + 'px';
border.style.top = startY + 'px';
- var onMouseMove = function(event) {
- var inRect = this.getBoundingClientRect();
- var x = event.clientX - inRect.left + this.scrollLeft;
- var y = event.clientY - inRect.top + this.scrollTop;
+ const onMouseMove = function(event) {
+ const inRect = this.getBoundingClientRect();
+ const x = event.clientX - inRect.left + this.scrollLeft;
+ const y = event.clientY - inRect.top + this.scrollTop;
border.style.left = Math.min(startX, x) + 'px';
border.style.top = Math.min(startY, y) + 'px';
border.style.width = Math.abs(startX - x) + 'px';
border.style.height = Math.abs(startY - y) + 'px';
}.bind(this);
- var onMouseUp = function() {
+ const onMouseUp = function() {
this.removeChild(border);
document.removeEventListener('mousemove', onMouseMove, true);
document.removeEventListener('mouseup', onMouseUp, true);
@@ -1328,16 +1373,18 @@ cr.define('cr.ui', function() {
*/
function handleMouseDown(e) {
e.target = /** @type {!HTMLElement} */ (e.target);
- var listItem = this.getListItemAncestor(e.target);
- var wasSelected = listItem && listItem.selected;
+ const listItem = this.getListItemAncestor(e.target);
+ const wasSelected = listItem && listItem.selected;
this.handlePointerDownUp_(e);
- if (e.defaultPrevented || e.button != 0)
+ if (e.defaultPrevented || e.button != 0) {
return;
+ }
// The following hack is required only if the listItem gets selected.
- if (!listItem || wasSelected || !listItem.selected)
+ if (!listItem || wasSelected || !listItem.selected) {
return;
+ }
// If non-focusable area in a list item is clicked and the item still
// contains the focused element, the item did a special focus handling
@@ -1360,18 +1407,22 @@ cr.define('cr.ui', function() {
*/
function handleDragStart(e) {
e = /** @type {MouseEvent} */ (e);
- var element = e.target.ownerDocument.elementFromPoint(e.clientX, e.clientY);
- var listItem = this.getListItemAncestor(element);
- if (!listItem)
+ const element =
+ e.target.ownerDocument.elementFromPoint(e.clientX, e.clientY);
+ const listItem = this.getListItemAncestor(element);
+ if (!listItem) {
return;
+ }
- var index = this.getIndexOfListItem(listItem);
- if (index == -1)
+ const index = this.getIndexOfListItem(listItem);
+ if (index == -1) {
return;
+ }
- var isAlreadySelected = this.selectionModel_.getIndexSelected(index);
- if (!isAlreadySelected)
+ const isAlreadySelected = this.selectionModel_.getIndexSelected(index);
+ if (!isAlreadySelected) {
this.selectionModel_.selectedIndex = index;
+ }
}
/**
@@ -1382,10 +1433,11 @@ cr.define('cr.ui', function() {
* @return {boolean} True if we found a focusable element.
*/
function containsFocusableElement(start, root) {
- for (var element = start; element && element != root;
+ for (let element = start; element && element != root;
element = element.parentElement) {
- if (element.tabIndex >= 0 && !element.disabled)
+ if (element.tabIndex >= 0 && !element.disabled) {
return true;
+ }
}
return false;
}
diff --git a/chromium/ui/webui/resources/js/cr/ui/list_item.js b/chromium/ui/webui/resources/js/cr/ui/list_item.js
index 45ff813b2f4..319c2facf6f 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list_item.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list_item.js
@@ -9,7 +9,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLLIElement}
*/
- var ListItem = cr.ui.define('li');
+ const ListItem = cr.ui.define('li');
/**
* The next id suffix to use when giving each item an unique id.
@@ -43,8 +43,9 @@ cr.define('cr.ui', function() {
*/
decorate: function() {
this.setAttribute('role', 'listitem');
- if (!this.id)
+ if (!this.id) {
this.id = 'listitem-' + ListItem.nextUniqueIdSuffix_++;
+ }
},
/**
diff --git a/chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js b/chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js
index 30ef24871fd..8b638f96b0e 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js
@@ -36,8 +36,9 @@ cr.define('cr.ui', function() {
* @return {number} The index below or -1 if not found.
*/
getIndexBelow: function(index) {
- if (index == this.getLastIndex())
+ if (index == this.getLastIndex()) {
return -1;
+ }
return index + 1;
},
@@ -81,8 +82,9 @@ cr.define('cr.ui', function() {
* @return {number} The next index or -1 if not found.
*/
getNextIndex: function(index) {
- if (index == this.getLastIndex())
+ if (index == this.getLastIndex()) {
return -1;
+ }
return index + 1;
},
@@ -118,9 +120,9 @@ cr.define('cr.ui', function() {
* none.
*/
handlePointerDownUp: function(e, index) {
- var sm = this.selectionModel;
- var anchorIndex = sm.anchorIndex;
- var isDown = (e.type == 'mousedown');
+ const sm = this.selectionModel;
+ const anchorIndex = sm.anchorIndex;
+ const isDown = (e.type == 'mousedown');
sm.beginChange();
@@ -131,11 +133,13 @@ cr.define('cr.ui', function() {
if (cr.isMac || cr.isChromeOS) {
sm.leadIndex = sm.anchorIndex = -1;
sm.unselectAll();
- } else if (!isDown && !e.shiftKey && !e.ctrlKey)
+ } else if (!isDown && !e.shiftKey && !e.ctrlKey) {
// Keep anchor and lead indexes. Note that this is intentionally
// different than on the Mac.
- if (sm.multiple)
+ if (sm.multiple) {
sm.unselectAll();
+ }
+ }
} else {
if (sm.multiple &&
(cr.isMac ? e.metaKey : (e.ctrlKey && !e.shiftKey))) {
@@ -151,17 +155,18 @@ cr.define('cr.ui', function() {
if (isDown) {
sm.unselectAll();
sm.leadIndex = index;
- if (sm.multiple)
+ if (sm.multiple) {
sm.selectRange(anchorIndex, index);
- else
+ } else {
sm.setIndexSelected(index, true);
+ }
}
} else {
// Right click for a context menu needs to not clear the selection.
- var isRightClick = e.button == 2;
+ const isRightClick = e.button == 2;
// If the index is selected this is handled in mouseup.
- var indexSelected = sm.getIndexSelected(index);
+ const indexSelected = sm.getIndexSelected(index);
if ((indexSelected && !isDown || !indexSelected && isDown) &&
!(indexSelected && isRightClick)) {
sm.selectedIndex = index;
@@ -191,16 +196,17 @@ cr.define('cr.ui', function() {
* @param {Event} e The keydown event.
*/
handleKeyDown: function(e) {
- var tagName = e.target.tagName;
+ const tagName = e.target.tagName;
// If focus is in an input field of some kind, only handle navigation keys
// that aren't likely to conflict with input interaction (e.g., text
// editing, or changing the value of a checkbox or select).
if (tagName == 'INPUT') {
- var inputType = e.target.type;
+ const inputType = e.target.type;
// Just protect space (for toggling) for checkbox and radio.
if (inputType == 'checkbox' || inputType == 'radio') {
- if (e.key == ' ')
+ if (e.key == ' ') {
return;
+ }
// Protect all but the most basic navigation commands in anything
// else.
} else if (e.key != 'ArrowUp' && e.key != 'ArrowDown') {
@@ -208,13 +214,14 @@ cr.define('cr.ui', function() {
}
}
// Similarly, don't interfere with select element handling.
- if (tagName == 'SELECT')
+ if (tagName == 'SELECT') {
return;
+ }
- var sm = this.selectionModel;
- var newIndex = -1;
- var leadIndex = sm.leadIndex;
- var prevent = true;
+ const sm = this.selectionModel;
+ let newIndex = -1;
+ const leadIndex = sm.leadIndex;
+ let prevent = true;
// Ctrl/Meta+A
if (sm.multiple && e.keyCode == 65 &&
@@ -226,7 +233,7 @@ cr.define('cr.ui', function() {
if (e.key == ' ') {
if (leadIndex != -1) {
- var selected = sm.getIndexSelected(leadIndex);
+ const selected = sm.getIndexSelected(leadIndex);
if (e.ctrlKey || !selected) {
sm.setIndexSelected(leadIndex, !selected || !sm.multiple);
return;
@@ -268,9 +275,10 @@ cr.define('cr.ui', function() {
sm.leadIndex = newIndex;
if (e.shiftKey) {
- var anchorIndex = sm.anchorIndex;
- if (sm.multiple)
+ const anchorIndex = sm.anchorIndex;
+ if (sm.multiple) {
sm.unselectAll();
+ }
if (anchorIndex == -1) {
sm.setIndexSelected(newIndex, true);
sm.anchorIndex = newIndex;
@@ -281,16 +289,18 @@ cr.define('cr.ui', function() {
// Setting the lead index is done above.
// Mac does not allow you to change the lead.
} else {
- if (sm.multiple)
+ if (sm.multiple) {
sm.unselectAll();
+ }
sm.setIndexSelected(newIndex, true);
sm.anchorIndex = newIndex;
}
sm.endChange();
- if (prevent)
+ if (prevent) {
e.preventDefault();
+ }
}
}
};
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 9f293041a02..7046cfb68f5 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
@@ -3,7 +3,7 @@
// found in the LICENSE file.
cr.define('cr.ui', function() {
- /** @const */ var EventTarget = cr.EventTarget;
+ /** @const */ const EventTarget = cr.EventTarget;
/**
* Creates a new selection model that is to be used with lists.
@@ -44,35 +44,37 @@ cr.define('cr.ui', function() {
},
set selectedIndexes(selectedIndexes) {
this.beginChange();
- var unselected = {};
- for (var index in this.selectedIndexes_) {
+ const unselected = {};
+ for (const index in this.selectedIndexes_) {
unselected[index] = true;
}
- for (var i = 0; i < selectedIndexes.length; i++) {
- var index = selectedIndexes[i];
+ for (let i = 0; i < selectedIndexes.length; i++) {
+ const index = selectedIndexes[i];
if (index in this.selectedIndexes_) {
delete unselected[index];
} else {
this.selectedIndexes_[index] = true;
// Mark the index as changed. If previously marked, then unmark,
// since it just got reverted to the original state.
- if (index in this.changedIndexes_)
+ if (index in this.changedIndexes_) {
delete this.changedIndexes_[index];
- else
+ } else {
this.changedIndexes_[index] = true;
+ }
}
}
- for (var index in unselected) {
+ for (let index in unselected) {
index = +index;
delete this.selectedIndexes_[index];
// Mark the index as changed. If previously marked, then unmark,
// since it just got reverted to the original state.
- if (index in this.changedIndexes_)
+ if (index in this.changedIndexes_) {
delete this.changedIndexes_[index];
- else
+ } else {
this.changedIndexes_[index] = false;
+ }
}
if (selectedIndexes.length) {
@@ -89,7 +91,7 @@ cr.define('cr.ui', function() {
* @type {number}
*/
get selectedIndex() {
- for (var i in this.selectedIndexes_) {
+ for (const i in this.selectedIndexes_) {
return Number(i);
}
return -1;
@@ -114,10 +116,11 @@ cr.define('cr.ui', function() {
return -1;
}
- var result = Infinity;
- for (var i in this.selectedIndexes_) {
- if (Math.abs(i - index) < Math.abs(result - index))
+ let result = Infinity;
+ for (const i in this.selectedIndexes_) {
+ if (Math.abs(i - index) < Math.abs(result - index)) {
result = i;
+ }
}
return result < this.length ? Number(result) : -1;
},
@@ -131,14 +134,14 @@ cr.define('cr.ui', function() {
selectRange: function(start, end) {
// Swap if starts comes after end.
if (start > end) {
- var tmp = start;
+ const tmp = start;
start = end;
end = tmp;
}
this.beginChange();
- for (var index = start; index != end; index++) {
+ for (let index = start; index != end; index++) {
this.setIndexSelected(index, true);
}
this.setIndexSelected(end, true);
@@ -150,8 +153,9 @@ cr.define('cr.ui', function() {
* Selects all indexes.
*/
selectAll: function() {
- if (this.length === 0)
+ if (this.length === 0) {
return;
+ }
this.selectRange(0, this.length - 1);
},
@@ -172,7 +176,7 @@ cr.define('cr.ui', function() {
*/
unselectAll: function() {
this.beginChange();
- for (var i in this.selectedIndexes_) {
+ for (const i in this.selectedIndexes_) {
this.setIndexSelected(+i, false);
}
this.endChange();
@@ -184,14 +188,16 @@ cr.define('cr.ui', function() {
* @param {boolean} b Whether to select the index or not.
*/
setIndexSelected: function(index, b) {
- var oldSelected = index in this.selectedIndexes_;
- if (oldSelected == b)
+ const oldSelected = index in this.selectedIndexes_;
+ if (oldSelected == b) {
return;
+ }
- if (b)
+ if (b) {
this.selectedIndexes_[index] = true;
- else
+ } else {
delete this.selectedIndexes_[index];
+ }
this.beginChange();
@@ -247,9 +253,9 @@ cr.define('cr.ui', function() {
}
this.oldAnchorIndex_ = null;
- var indexes = Object.keys(this.changedIndexes_);
+ const indexes = Object.keys(this.changedIndexes_);
if (indexes.length) {
- var e = new Event('change');
+ const e = new Event('change');
e.changes = indexes.map(function(index) {
return {
index: Number(index),
@@ -274,12 +280,13 @@ cr.define('cr.ui', function() {
return this.leadIndex_;
},
set leadIndex(leadIndex) {
- var oldValue = this.leadIndex_;
- var newValue = this.adjustIndex_(leadIndex);
+ const oldValue = this.leadIndex_;
+ const newValue = this.adjustIndex_(leadIndex);
this.leadIndex_ = newValue;
// Delays the call of dispatchPropertyChange if batch is running.
- if (!this.changeCount_ && newValue != oldValue)
+ if (!this.changeCount_ && newValue != oldValue) {
cr.dispatchPropertyChange(this, 'leadIndex', newValue, oldValue);
+ }
},
anchorIndex_: -1,
@@ -293,12 +300,13 @@ cr.define('cr.ui', function() {
return this.anchorIndex_;
},
set anchorIndex(anchorIndex) {
- var oldValue = this.anchorIndex_;
- var newValue = this.adjustIndex_(anchorIndex);
+ const oldValue = this.anchorIndex_;
+ const newValue = this.adjustIndex_(anchorIndex);
this.anchorIndex_ = newValue;
// Delays the call of dispatchPropertyChange if batch is running.
- if (!this.changeCount_ && newValue != oldValue)
+ if (!this.changeCount_ && newValue != oldValue) {
cr.dispatchPropertyChange(this, 'anchorIndex', newValue, oldValue);
+ }
},
/**
@@ -313,7 +321,7 @@ cr.define('cr.ui', function() {
// selected items. This rule is not enforces until end of batch update.
if (!this.changeCount_ && !this.independentLeadItem_ &&
!this.getIndexSelected(index)) {
- var index2 = this.getNearestSelectedIndex_(index);
+ const index2 = this.getNearestSelectedIndex_(index);
index = index2;
}
return index;
@@ -333,9 +341,9 @@ cr.define('cr.ui', function() {
*/
adjustToReordering: function(permutation) {
this.beginChange();
- var oldLeadIndex = this.leadIndex;
- var oldAnchorIndex = this.anchorIndex;
- var oldSelectedItemsCount = this.selectedIndexes.length;
+ const oldLeadIndex = this.leadIndex;
+ const oldAnchorIndex = this.anchorIndex;
+ const oldSelectedItemsCount = this.selectedIndexes.length;
this.selectedIndexes = this.selectedIndexes
.map(function(oldIndex) {
@@ -346,10 +354,12 @@ cr.define('cr.ui', function() {
});
// Will be adjusted in endChange.
- if (oldLeadIndex != -1)
+ if (oldLeadIndex != -1) {
this.leadIndex = permutation[oldLeadIndex];
- if (oldAnchorIndex != -1)
+ }
+ if (oldAnchorIndex != -1) {
this.anchorIndex = permutation[oldAnchorIndex];
+ }
if (oldSelectedItemsCount && !this.selectedIndexes.length &&
this.length_ && oldLeadIndex != -1) {
diff --git a/chromium/ui/webui/resources/js/cr/ui/list_single_selection_model.js b/chromium/ui/webui/resources/js/cr/ui/list_single_selection_model.js
index 15865d0363e..859247ef7a7 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list_single_selection_model.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list_single_selection_model.js
@@ -3,7 +3,7 @@
// found in the LICENSE file.
cr.define('cr.ui', function() {
- /** @const */ var EventTarget = cr.EventTarget;
+ /** @const */ const EventTarget = cr.EventTarget;
/**
* Creates a new selection model that is to be used with lists. This only
@@ -37,7 +37,7 @@ cr.define('cr.ui', function() {
* @type {!Array} The selected indexes.
*/
get selectedIndexes() {
- var i = this.selectedIndex;
+ const i = this.selectedIndex;
return i != -1 ? [this.selectedIndex] : [];
},
set selectedIndexes(indexes) {
@@ -53,8 +53,8 @@ cr.define('cr.ui', function() {
return this.selectedIndex_;
},
set selectedIndex(selectedIndex) {
- var oldSelectedIndex = this.selectedIndex;
- var i = Math.max(-1, Math.min(this.length_ - 1, selectedIndex));
+ const oldSelectedIndex = this.selectedIndex;
+ const i = Math.max(-1, Math.min(this.length_ - 1, selectedIndex));
if (i != oldSelectedIndex) {
this.beginChange();
@@ -106,14 +106,16 @@ cr.define('cr.ui', function() {
*/
setIndexSelected: function(index, b) {
// Only allow selection
- var oldSelected = index == this.selectedIndex_;
- if (oldSelected == b)
+ const oldSelected = index == this.selectedIndex_;
+ if (oldSelected == b) {
return;
+ }
- if (b)
+ if (b) {
this.selectedIndex = index;
- else if (index == this.selectedIndex_)
+ } else if (index == this.selectedIndex_) {
this.selectedIndex = -1;
+ }
},
/**
@@ -145,11 +147,12 @@ cr.define('cr.ui', function() {
this.changeCount_--;
if (!this.changeCount_) {
if (this.selectedIndexBefore_ != this.selectedIndex_) {
- var beforeChange = this.createChangeEvent('beforeChange');
- if (this.dispatchEvent(beforeChange))
+ const beforeChange = this.createChangeEvent('beforeChange');
+ if (this.dispatchEvent(beforeChange)) {
this.dispatchEvent(this.createChangeEvent('change'));
- else
+ } else {
this.selectedIndex_ = this.selectedIndexBefore_;
+ }
}
}
},
@@ -159,8 +162,8 @@ cr.define('cr.ui', function() {
* @param {string} eventName Event name.
*/
createChangeEvent: function(eventName) {
- var e = new Event(eventName);
- var indexes = [this.selectedIndexBefore_, this.selectedIndex_];
+ const e = new Event(eventName);
+ const indexes = [this.selectedIndexBefore_, this.selectedIndex_];
e.changes =
indexes
.filter(function(index) {
@@ -184,9 +187,9 @@ cr.define('cr.ui', function() {
return this.leadIndex_;
},
set leadIndex(leadIndex) {
- var li = this.adjustIndex_(leadIndex);
+ const li = this.adjustIndex_(leadIndex);
if (li != this.leadIndex_) {
- var oldLeadIndex = this.leadIndex_;
+ const oldLeadIndex = this.leadIndex_;
this.leadIndex_ = li;
cr.dispatchPropertyChange(this, 'leadIndex', li, oldLeadIndex);
cr.dispatchPropertyChange(this, 'anchorIndex', li, oldLeadIndex);
@@ -195,8 +198,9 @@ cr.define('cr.ui', function() {
adjustIndex_: function(index) {
index = Math.max(-1, Math.min(this.length_ - 1, index));
- if (!this.independentLeadItem_)
+ if (!this.independentLeadItem_) {
index = this.selectedIndex;
+ }
return index;
},
@@ -224,10 +228,11 @@ cr.define('cr.ui', function() {
* @param {!Array<number>} permutation The reordering permutation.
*/
adjustToReordering: function(permutation) {
- if (this.leadIndex != -1)
+ if (this.leadIndex != -1) {
this.leadIndex = permutation[this.leadIndex];
+ }
- var oldSelectedIndex = this.selectedIndex;
+ const oldSelectedIndex = this.selectedIndex;
if (oldSelectedIndex != -1) {
this.selectedIndex = permutation[oldSelectedIndex];
}
diff --git a/chromium/ui/webui/resources/js/cr/ui/menu.js b/chromium/ui/webui/resources/js/cr/ui/menu.js
index 7560a63fb4f..7d320f508b1 100644
--- a/chromium/ui/webui/resources/js/cr/ui/menu.js
+++ b/chromium/ui/webui/resources/js/cr/ui/menu.js
@@ -3,8 +3,7 @@
// found in the LICENSE file.
cr.define('cr.ui', function() {
-
- /** @const */ var MenuItem = cr.ui.MenuItem;
+ /** @const */ const MenuItem = cr.ui.MenuItem;
/**
* Creates a new menu element. Menu dispatches all commands on the element it
@@ -14,7 +13,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var Menu = cr.ui.define('cr-menu');
+ const Menu = cr.ui.define('cr-menu');
Menu.prototype = {
__proto__: HTMLElement.prototype,
@@ -39,8 +38,8 @@ cr.define('cr.ui', function() {
this.hidden = true; // Hide the menu by default.
// Decorate the children as menu items.
- var menuItems = this.menuItems;
- for (var i = 0, menuItem; menuItem = menuItems[i]; i++) {
+ const menuItems = this.menuItems;
+ for (let i = 0, menuItem; menuItem = menuItems[i]; i++) {
cr.ui.decorate(menuItem, MenuItem);
}
},
@@ -51,16 +50,18 @@ cr.define('cr.ui', function() {
* @return {cr.ui.MenuItem} The created menu item.
*/
addMenuItem: function(item) {
- var menuItem = this.ownerDocument.createElement('cr-menu-item');
+ const menuItem = this.ownerDocument.createElement('cr-menu-item');
this.appendChild(menuItem);
cr.ui.decorate(menuItem, MenuItem);
- if (item.label)
+ if (item.label) {
menuItem.label = item.label;
+ }
- if (item.iconUrl)
+ if (item.iconUrl) {
menuItem.iconUrl = item.iconUrl;
+ }
return menuItem;
},
@@ -69,7 +70,7 @@ cr.define('cr.ui', function() {
* Adds separator at the end of the list.
*/
addSeparator: function() {
- var separator = this.ownerDocument.createElement('hr');
+ const separator = this.ownerDocument.createElement('hr');
cr.ui.decorate(separator, MenuItem);
this.appendChild(separator);
},
@@ -102,7 +103,7 @@ cr.define('cr.ui', function() {
* @private
*/
handleMouseOver_: function(e) {
- var overItem = this.findMenuItem_(/** @type {Element} */ (e.target));
+ const overItem = this.findMenuItem_(/** @type {Element} */ (e.target));
this.selectedItem = overItem;
},
@@ -125,12 +126,15 @@ cr.define('cr.ui', function() {
handleMouseUp_: function(e) {
assert(this.contains(/** @type {Element} */ (e.target)));
- if (!this.trustEvent_(e) || Date.now() - this.shown_.time > 200)
+ if (!this.trustEvent_(e) || Date.now() - this.shown_.time > 200) {
return;
+ }
- var pos = this.shown_.mouseDownPos;
- if (!pos || Math.abs(pos.x - e.screenX) + Math.abs(pos.y - e.screenY) > 4)
+ const pos = this.shown_.mouseDownPos;
+ if (!pos ||
+ Math.abs(pos.x - e.screenX) + Math.abs(pos.y - e.screenY) > 4) {
return;
+ }
e.preventDefault();
e.stopPropagation();
@@ -158,7 +162,7 @@ cr.define('cr.ui', function() {
return this.menuItems[this.selectedIndex];
},
set selectedItem(item) {
- var index = Array.prototype.indexOf.call(this.menuItems, item);
+ const index = Array.prototype.indexOf.call(this.menuItems, item);
this.selectedIndex = index;
},
@@ -192,10 +196,12 @@ cr.define('cr.ui', function() {
* @private
*/
isItemVisible_: function(menuItem) {
- if (menuItem.hidden)
+ if (menuItem.hidden) {
return false;
- if (!!menuItem.offsetParent)
+ }
+ if (!!menuItem.offsetParent) {
return true;
+ }
// A "position: fixed" element won't have an offsetParent, so we have to
// do the full style computation.
return window.getComputedStyle(menuItem).display != 'none';
@@ -208,7 +214,7 @@ cr.define('cr.ui', function() {
hasVisibleItems: function() {
// Inspect items in reverse order to determine if the separator above each
// set of items is required.
- for (let menuItem of this.menuItems) {
+ for (const menuItem of this.menuItems) {
if (this.isItemVisible_(menuItem)) {
return true;
}
@@ -223,17 +229,17 @@ cr.define('cr.ui', function() {
* @return {boolean} Whether the event was handled be the menu.
*/
handleKeyDown: function(e) {
- var item = this.selectedItem;
+ let item = this.selectedItem;
- var self = this;
- var selectNextAvailable = function(m) {
- var menuItems = self.menuItems;
- var len = menuItems.length;
+ const self = this;
+ const selectNextAvailable = function(m) {
+ const menuItems = self.menuItems;
+ const len = menuItems.length;
if (!len) {
// Edge case when there are no items.
return;
}
- var i = self.selectedIndex;
+ let i = self.selectedIndex;
if (i == -1 && m == -1) {
// Edge case when needed to go the last item first.
i = 0;
@@ -242,23 +248,26 @@ cr.define('cr.ui', function() {
// "i" may be negative(-1), so modulus operation and cycle below
// wouldn't work as assumed. This trick makes startPosition positive
// without altering it's modulo.
- var startPosition = (i + len) % len;
+ const startPosition = (i + len) % len;
while (true) {
i = (i + m + len) % len;
// Check not to enter into infinite loop if all items are hidden or
// disabled.
- if (i == startPosition)
+ if (i == startPosition) {
break;
+ }
item = menuItems[i];
if (item && !item.isSeparator() && !item.disabled &&
- this.isItemVisible_(item))
+ this.isItemVisible_(item)) {
break;
+ }
}
- if (item && !item.disabled)
+ if (item && !item.disabled) {
self.selectedIndex = i;
+ }
}.bind(this);
switch (e.key) {
@@ -275,13 +284,14 @@ cr.define('cr.ui', function() {
if (item) {
// Store |contextElement| since it'll be removed when handling the
// 'activate' event.
- var contextElement = this.contextElement;
- var activationEvent = cr.doc.createEvent('Event');
+ const contextElement = this.contextElement;
+ const activationEvent = cr.doc.createEvent('Event');
activationEvent.initEvent('activate', true, true);
activationEvent.originalEvent = e;
if (item.dispatchEvent(activationEvent)) {
- if (item.command)
+ if (item.command) {
item.command.execute(contextElement);
+ }
}
}
return true;
@@ -306,18 +316,19 @@ cr.define('cr.ui', function() {
* @param {Node=} node Node for which to actuate commands state.
*/
updateCommands: function(node) {
- var menuItems = this.menuItems;
+ const menuItems = this.menuItems;
- for (var i = 0, menuItem; menuItem = menuItems[i]; i++) {
- if (!menuItem.isSeparator())
+ for (const menuItem of menuItems) {
+ 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) {
+ for (const menuItem of menuItems) {
if (menuItem.isSeparator()) {
if (separatorRequired) {
lastSeparator = menuItem;
@@ -337,14 +348,15 @@ cr.define('cr.ui', function() {
};
function selectedIndexChanged(selectedIndex, oldSelectedIndex) {
- var oldSelectedItem = this.menuItems[oldSelectedIndex];
+ const oldSelectedItem = this.menuItems[oldSelectedIndex];
if (oldSelectedItem) {
oldSelectedItem.selected = false;
oldSelectedItem.blur();
}
- var item = this.selectedItem;
- if (item)
+ const item = this.selectedItem;
+ if (item) {
item.selected = true;
+ }
}
/**
diff --git a/chromium/ui/webui/resources/js/cr/ui/menu_button.js b/chromium/ui/webui/resources/js/cr/ui/menu_button.js
index 686408b93d2..33dc00c3d49 100644
--- a/chromium/ui/webui/resources/js/cr/ui/menu_button.js
+++ b/chromium/ui/webui/resources/js/cr/ui/menu_button.js
@@ -18,13 +18,13 @@ cr.ui.HideType = {
cr.define('cr.ui', function() {
/** @const */
- var Menu = cr.ui.Menu;
+ const Menu = cr.ui.Menu;
/** @const */
- var HideType = cr.ui.HideType;
+ const HideType = cr.ui.HideType;
/** @const */
- var positionPopupAroundElement = cr.ui.positionPopupAroundElement;
+ const positionPopupAroundElement = cr.ui.positionPopupAroundElement;
/**
* Creates a new menu button element.
@@ -33,7 +33,7 @@ cr.define('cr.ui', function() {
* @extends {HTMLButtonElement}
* @implements {EventListener}
*/
- var MenuButton = cr.ui.define('button');
+ const MenuButton = cr.ui.define('button');
MenuButton.prototype = {
__proto__: HTMLButtonElement.prototype,
@@ -55,9 +55,10 @@ cr.define('cr.ui', function() {
this.classList.add('custom-appearance');
this.classList.add('menu-button'); // For styles in menu_button.css.
- var menu;
- if ((menu = this.getAttribute('menu')))
+ let menu;
+ if ((menu = this.getAttribute('menu'))) {
this.menu = menu;
+ }
// An event tracker for events we only connect to while the menu is
// displayed.
@@ -82,8 +83,9 @@ cr.define('cr.ui', function() {
this.menu_ = menu;
if (menu) {
- if (menu.id)
+ if (menu.id) {
this.setAttribute('menu', '#' + menu.id);
+ }
}
},
@@ -112,8 +114,9 @@ cr.define('cr.ui', function() {
* @param {Event} e The event object.
*/
handleEvent: function(e) {
- if (!this.menu)
+ if (!this.menu) {
return;
+ }
switch (e.type) {
case 'touchstart':
@@ -171,9 +174,9 @@ cr.define('cr.ui', function() {
this.classList.remove('using-mouse');
break;
case 'activate':
- var hideDelayed =
+ const hideDelayed =
e.target instanceof cr.ui.MenuItem && e.target.checkable;
- var hideType = hideDelayed ? HideType.DELAYED : HideType.INSTANT;
+ const hideType = hideDelayed ? HideType.DELAYED : HideType.INSTANT;
if (e.originalEvent instanceof MouseEvent ||
e.originalEvent instanceof TouchEvent) {
this.hideMenuWithoutTakingFocus_(hideType);
@@ -183,8 +186,9 @@ cr.define('cr.ui', function() {
}
break;
case 'scroll':
- if (!(e.target == this.menu || this.menu.contains(e.target)))
+ if (!(e.target == this.menu || this.menu.contains(e.target))) {
this.hideMenu();
+ }
break;
case 'popstate':
case 'resize':
@@ -192,8 +196,9 @@ cr.define('cr.ui', function() {
break;
case 'contextmenu':
if ((!this.menu || !this.menu.contains(e.target)) &&
- (!this.hideTimestamp_ || Date.now() - this.hideTimestamp_ > 50))
+ (!this.hideTimestamp_ || Date.now() - this.hideTimestamp_ > 50)) {
this.showMenu(true, {x: e.screenX, y: e.screenY});
+ }
e.preventDefault();
// Don't allow elements further up in the DOM to show their menus.
e.stopPropagation();
@@ -218,18 +223,19 @@ cr.define('cr.ui', function() {
this.menu.updateCommands(this);
- var event = new UIEvent(
+ const event = new UIEvent(
'menushow', {bubbles: true, cancelable: true, view: window});
- if (!this.dispatchEvent(event))
+ if (!this.dispatchEvent(event)) {
return;
+ }
this.menu.show(opt_mousePos);
this.setAttribute('menu-shown', '');
// When the menu is shown we steal all keyboard events.
- var doc = this.ownerDocument;
- var win = doc.defaultView;
+ const doc = this.ownerDocument;
+ const win = doc.defaultView;
this.showingEvents_.add(doc, 'keydown', this, true);
this.showingEvents_.add(doc, 'mousedown', this, true);
this.showingEvents_.add(doc, 'focus', this, true);
@@ -240,8 +246,9 @@ cr.define('cr.ui', function() {
this.showingEvents_.add(this.menu, 'activate', this);
this.positionMenu_();
- if (shouldSetFocus)
+ if (shouldSetFocus) {
this.menu.focusSelectedItem();
+ }
},
/**
@@ -272,21 +279,24 @@ cr.define('cr.ui', function() {
* default: cr.ui.HideType.INSTANT.
*/
hideMenuInternal_: function(shouldTakeFocus, opt_hideType) {
- if (!this.isMenuShown())
+ if (!this.isMenuShown()) {
return;
+ }
this.removeAttribute('menu-shown');
- if (opt_hideType == HideType.DELAYED)
+ if (opt_hideType == HideType.DELAYED) {
this.menu.classList.add('hide-delayed');
- else
+ } else {
this.menu.classList.remove('hide-delayed');
+ }
this.menu.hide();
this.showingEvents_.removeAll();
- if (shouldTakeFocus)
+ if (shouldTakeFocus) {
this.focus();
+ }
- var event = new UIEvent(
+ const event = new UIEvent(
'menuhide', {bubbles: true, cancelable: false, view: window});
this.dispatchEvent(event);
@@ -320,12 +330,14 @@ cr.define('cr.ui', function() {
switch (e.key) {
case 'ArrowDown':
case 'ArrowUp':
- if (!this.respondToArrowKeys)
+ if (!this.respondToArrowKeys) {
break;
+ }
case 'Enter':
case ' ':
- if (!this.isMenuShown())
+ if (!this.isMenuShown()) {
this.showMenu(true);
+ }
e.preventDefault();
break;
case 'Escape':
diff --git a/chromium/ui/webui/resources/js/cr/ui/menu_item.js b/chromium/ui/webui/resources/js/cr/ui/menu_item.js
index 17f2783c3e2..ca0288c403a 100644
--- a/chromium/ui/webui/resources/js/cr/ui/menu_item.js
+++ b/chromium/ui/webui/resources/js/cr/ui/menu_item.js
@@ -3,7 +3,7 @@
// found in the LICENSE file.
cr.define('cr.ui', function() {
- /** @const */ var Command = cr.ui.Command;
+ /** @const */ const Command = cr.ui.Command;
/**
* Creates a new menu item element.
@@ -12,14 +12,14 @@ cr.define('cr.ui', function() {
* @extends {HTMLElement}
* @implements {EventListener}
*/
- var MenuItem = cr.ui.define('cr-menu-item');
+ const MenuItem = cr.ui.define('cr-menu-item');
/**
* Creates a new menu separator element.
* @return {cr.ui.MenuItem} The new separator element.
*/
MenuItem.createSeparator = function() {
- var el = cr.doc.createElement('hr');
+ const el = cr.doc.createElement('hr');
MenuItem.decorate(el);
return el;
};
@@ -31,9 +31,10 @@ cr.define('cr.ui', function() {
* Initializes the menu item.
*/
decorate: function() {
- var commandId;
- if ((commandId = this.getAttribute('command')))
+ let commandId;
+ if ((commandId = this.getAttribute('command'))) {
this.command = commandId;
+ }
this.addEventListener('mouseup', this.handleMouseUp_);
@@ -43,12 +44,14 @@ cr.define('cr.ui', function() {
// Enable Text to Speech on the menu. Additionaly, ID has to be set, since
// it is used in element's aria-activedescendant attribute.
- if (!this.isSeparator())
+ if (!this.isSeparator()) {
this.setAttribute('role', 'menuitem');
+ }
- var iconUrl;
- if ((iconUrl = this.getAttribute('icon')))
+ let iconUrl;
+ if ((iconUrl = this.getAttribute('icon'))) {
this.iconUrl = iconUrl;
+ }
},
/**
@@ -76,11 +79,13 @@ cr.define('cr.ui', function() {
this.command_ = command;
if (command) {
- if (command.id)
+ if (command.id) {
this.setAttribute('command', '#' + command.id);
+ }
- if (typeof command.label === 'string')
+ if (typeof command.label === 'string') {
this.label = command.label;
+ }
this.disabled = command.disabled;
this.hidden = command.hidden;
this.checked = command.checked;
@@ -131,19 +136,21 @@ cr.define('cr.ui', function() {
this.removeAttribute('shortcutText');
if (!this.command_ || !this.command_.shortcut ||
- this.command_.hideShortcutText)
+ this.command_.hideShortcutText) {
return;
+ }
- var shortcuts = this.command_.shortcut.split(/\s+/);
+ const shortcuts = this.command_.shortcut.split(/\s+/);
- if (shortcuts.length == 0)
+ if (shortcuts.length == 0) {
return;
+ }
- var shortcut = shortcuts[0];
- var mods = {};
- var ident = '';
+ const shortcut = shortcuts[0];
+ const mods = {};
+ let ident = '';
shortcut.split('|').forEach(function(part) {
- var partUc = part.toUpperCase();
+ const partUc = part.toUpperCase();
switch (partUc) {
case 'CTRL':
case 'ALT':
@@ -157,15 +164,17 @@ cr.define('cr.ui', function() {
}
});
- var shortcutText = '';
+ let shortcutText = '';
['CTRL', 'ALT', 'SHIFT', 'META'].forEach(function(mod) {
- if (mods[mod])
+ if (mods[mod]) {
shortcutText += loadTimeData.getString('SHORTCUT_' + mod) + '+';
+ }
});
- if (ident == ' ')
+ if (ident == ' ') {
ident = 'Space';
+ }
if (ident.length != 1) {
shortcutText +=
@@ -186,21 +195,22 @@ cr.define('cr.ui', function() {
handleMouseUp_: function(e) {
e = /** @type {!MouseEvent} */ (e);
// Only dispatch an activate event for left or middle click.
- if (e.button > 1)
+ if (e.button > 1) {
return;
+ }
if (!this.disabled && !this.isSeparator() && this.selected) {
// Store |contextElement| since it'll be removed by {Menu} on handling
// 'activate' event.
- var contextElement =
+ const contextElement =
/** @type {{contextElement: Element}} */ (this.parentNode)
.contextElement;
- var activationEvent = cr.doc.createEvent('Event');
+ const activationEvent = cr.doc.createEvent('Event');
activationEvent.initEvent('activate', true, true);
activationEvent.originalEvent = e;
// Dispatch command event followed by executing the command object.
if (this.dispatchEvent(activationEvent)) {
- var command = this.command;
+ const command = this.command;
if (command) {
command.execute(contextElement);
cr.ui.swallowDoubleClick(e);
diff --git a/chromium/ui/webui/resources/js/cr/ui/node_utils.js b/chromium/ui/webui/resources/js/cr/ui/node_utils.js
index 21b0fb16dbc..ed5912af318 100644
--- a/chromium/ui/webui/resources/js/cr/ui/node_utils.js
+++ b/chromium/ui/webui/resources/js/cr/ui/node_utils.js
@@ -18,13 +18,13 @@ cr.ui.reverseButtonStrips = function(opt_root) {
return;
}
- var root = opt_root || document;
- var buttonStrips = root.querySelectorAll('.button-strip:not([reversed])');
- for (var j = 0; j < buttonStrips.length; j++) {
- var buttonStrip = buttonStrips[j];
+ const root = opt_root || document;
+ const buttonStrips = root.querySelectorAll('.button-strip:not([reversed])');
+ for (let j = 0; j < buttonStrips.length; j++) {
+ const buttonStrip = buttonStrips[j];
- var childNodes = buttonStrip.childNodes;
- for (var i = childNodes.length - 1; i >= 0; i--) {
+ const childNodes = buttonStrip.childNodes;
+ for (let i = childNodes.length - 1; i >= 0; i--) {
buttonStrip.appendChild(childNodes[i]);
}
@@ -38,15 +38,18 @@ cr.ui.reverseButtonStrips = function(opt_root) {
*/
cr.ui.setInitialFocus = function(root) {
// Do not change focus if any element in |root| is already focused.
- if (root.contains(document.activeElement))
+ if (root.contains(document.activeElement)) {
return;
+ }
- var elements = root.querySelectorAll('input, list, select, textarea, button');
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
+ const elements =
+ root.querySelectorAll('input, list, select, textarea, button');
+ for (let i = 0; i < elements.length; i++) {
+ const element = elements[i];
element.focus();
// .focus() isn't guaranteed to work. Continue until it does.
- if (document.activeElement == element)
+ if (document.activeElement == element) {
return;
+ }
}
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/overlay.js b/chromium/ui/webui/resources/js/cr/ui/overlay.js
index 16ad0ef4331..8a7e7db9f6a 100644
--- a/chromium/ui/webui/resources/js/cr/ui/overlay.js
+++ b/chromium/ui/webui/resources/js/cr/ui/overlay.js
@@ -13,7 +13,7 @@ cr.define('cr.ui.overlay', function() {
* @return {HTMLElement} The overlay.
*/
function getTopOverlay() {
- var overlays = /** @type !NodeList<!HTMLElement> */ (
+ const overlays = /** @type !NodeList<!HTMLElement> */ (
document.querySelectorAll('.overlay:not([hidden])'));
return overlays[overlays.length - 1];
}
@@ -29,17 +29,18 @@ cr.define('cr.ui.overlay', function() {
function isHidden(node) {
return node.hidden;
}
- var defaultButtons = /** @type !NodeList<!HTMLElement> */ (
+ const defaultButtons = /** @type !NodeList<!HTMLElement> */ (
overlay.querySelectorAll('.page .button-strip > .default-button'));
- for (var i = 0; i < defaultButtons.length; i++) {
- if (!findAncestor(defaultButtons[i], isHidden))
+ for (let i = 0; i < defaultButtons.length; i++) {
+ if (!findAncestor(defaultButtons[i], isHidden)) {
return defaultButtons[i];
+ }
}
return null;
}
/** @type {boolean} */
- var globallyInitialized = false;
+ let globallyInitialized = false;
/**
* Makes initializations which must hook at the document level.
@@ -47,20 +48,22 @@ cr.define('cr.ui.overlay', function() {
function globalInitialization() {
if (!globallyInitialized) {
document.addEventListener('keydown', function(e) {
- var overlay = getTopOverlay();
- if (!overlay)
+ const overlay = getTopOverlay();
+ if (!overlay) {
return;
+ }
// Close the overlay on escape.
- if (e.key == 'Escape')
+ if (e.key == 'Escape') {
cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
+ }
// Execute the overlay's default button on enter, unless focus is on an
// element that has standard behavior for the enter key.
- var forbiddenTagNames = /^(A|BUTTON|SELECT|TEXTAREA)$/;
+ const forbiddenTagNames = /^(A|BUTTON|SELECT|TEXTAREA)$/;
if (e.key == 'Enter' &&
!forbiddenTagNames.test(document.activeElement.tagName)) {
- var button = getDefaultButton(overlay);
+ const button = getDefaultButton(overlay);
if (button) {
button.click();
// Executing the default button may result in focus moving to a
@@ -83,11 +86,13 @@ cr.define('cr.ui.overlay', function() {
* height.
*/
function setMaxHeightAllPages() {
- var pages = document.querySelectorAll('.overlay .page:not(.not-resizable)');
+ const pages =
+ document.querySelectorAll('.overlay .page:not(.not-resizable)');
- var maxHeight = Math.min(0.9 * window.innerHeight, 640) + 'px';
- for (var i = 0; i < pages.length; i++)
+ const maxHeight = Math.min(0.9 * window.innerHeight, 640) + 'px';
+ for (let i = 0; i < pages.length; i++) {
pages[i].style.maxHeight = maxHeight;
+ }
}
/**
@@ -96,11 +101,12 @@ cr.define('cr.ui.overlay', function() {
*/
function setupOverlay(overlay) {
// Close the overlay on clicking any of the pages' close buttons.
- var closeButtons = overlay.querySelectorAll('.page > .close-button');
- for (var i = 0; i < closeButtons.length; i++) {
+ const closeButtons = overlay.querySelectorAll('.page > .close-button');
+ for (let i = 0; i < closeButtons.length; i++) {
closeButtons[i].addEventListener('click', function(e) {
- if (cr.ui.FocusOutlineManager)
+ if (cr.ui.FocusOutlineManager) {
cr.ui.FocusOutlineManager.forDocument(document).updateVisibility();
+ }
cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
});
}
@@ -108,10 +114,11 @@ cr.define('cr.ui.overlay', function() {
// Remove the 'pulse' animation any time the overlay is hidden or shown.
overlay.__defineSetter__('hidden', function(value) {
this.classList.remove('pulse');
- if (value)
+ if (value) {
this.setAttribute('hidden', true);
- else
+ } else {
this.removeAttribute('hidden');
+ }
});
overlay.__defineGetter__('hidden', function() {
return this.hasAttribute('hidden');
@@ -120,13 +127,15 @@ cr.define('cr.ui.overlay', function() {
// Shake when the user clicks away.
overlay.addEventListener('click', function(e) {
// Only pulse if the overlay was the target of the click.
- if (this != e.target)
+ if (this != e.target) {
return;
+ }
// This may be null while the overlay is closing.
- var overlayPage = this.querySelector('.page:not([hidden])');
- if (overlayPage)
+ const overlayPage = this.querySelector('.page:not([hidden])');
+ if (overlayPage) {
overlayPage.classList.add('pulse');
+ }
});
overlay.addEventListener('animationend', function(e) {
e.target.classList.remove('pulse');
diff --git a/chromium/ui/webui/resources/js/cr/ui/page_manager/BUILD.gn b/chromium/ui/webui/resources/js/cr/ui/page_manager/BUILD.gn
new file mode 100644
index 00000000000..3876abed3d1
--- /dev/null
+++ b/chromium/ui/webui/resources/js/cr/ui/page_manager/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":page",
+ ":page_manager",
+ ]
+}
+
+js_library("page") {
+ deps = [
+ "../:bubble",
+ "../:focus_outline_manager",
+ "../:node_utils",
+ "../:overlay",
+ "../..:event_target",
+ "../../..:cr",
+ "../../..:util",
+ ]
+}
+
+js_library("page_manager") {
+ deps = [
+ ":page",
+ "../../..:cr",
+ ]
+}
diff --git a/chromium/ui/webui/resources/js/cr/ui/page_manager/page.js b/chromium/ui/webui/resources/js/cr/ui/page_manager/page.js
index 5512e60a53c..c0b72d319d0 100644
--- a/chromium/ui/webui/resources/js/cr/ui/page_manager/page.js
+++ b/chromium/ui/webui/resources/js/cr/ui/page_manager/page.js
@@ -5,7 +5,7 @@
// <include src="../node_utils.js">
cr.define('cr.ui.pageManager', function() {
- var PageManager = cr.ui.pageManager.PageManager;
+ const PageManager = cr.ui.pageManager.PageManager;
/**
* Base class for pages that can be shown and hidden by PageManager. Each Page
@@ -107,8 +107,9 @@ cr.define('cr.ui.pageManager', function() {
* should include the leading '#' if not empty.
*/
setHash: function(hash) {
- if (this.hash == hash)
+ if (this.hash == hash) {
return;
+ }
this.hash = hash;
PageManager.onPageHashChanged(this);
},
@@ -155,8 +156,9 @@ cr.define('cr.ui.pageManager', function() {
if (this.isOverlay && this.container.classList.contains('transparent')) {
return false;
}
- if (this.pageDiv.hidden)
+ if (this.pageDiv.hidden) {
return false;
+ }
return this.pageDiv.page == this;
},
@@ -165,8 +167,9 @@ cr.define('cr.ui.pageManager', function() {
* @type {boolean}
*/
set visible(visible) {
- if ((this.visible && visible) || (!this.visible && !visible))
+ if ((this.visible && visible) || (!this.visible && !visible)) {
return;
+ }
// If using an overlay, the visibility of the dialog is toggled at the
// same time as the overlay to show the dialog's out transition. This
@@ -215,8 +218,8 @@ cr.define('cr.ui.pageManager', function() {
*/
setOverlayVisible_: function(visible) {
assert(this.isOverlay);
- var pageDiv = this.pageDiv;
- var container = this.container;
+ const pageDiv = this.pageDiv;
+ const container = this.container;
if (container.hidden != visible) {
if (visible) {
@@ -227,9 +230,10 @@ cr.define('cr.ui.pageManager', function() {
// Hide all dialogs in this container since a different one may have
// been previously visible before fading out.
- var pages = container.querySelectorAll('.page');
- for (var i = 0; i < pages.length; i++)
+ const pages = container.querySelectorAll('.page');
+ for (let i = 0; i < pages.length; i++) {
pages[i].hidden = true;
+ }
// Show the new dialog.
pageDiv.hidden = false;
pageDiv.page = this;
@@ -237,13 +241,13 @@ cr.define('cr.ui.pageManager', function() {
return;
}
- var self = this;
- var loading = PageManager.isLoading();
+ const self = this;
+ const loading = PageManager.isLoading();
if (!loading) {
// TODO(flackr): Use an event delegate to avoid having to subscribe and
// unsubscribe for transitionend events.
container.addEventListener('transitionend', function f(e) {
- var propName = e.propertyName;
+ const propName = e.propertyName;
if (e.target != e.currentTarget ||
(propName && propName != 'opacity')) {
return;
@@ -273,13 +277,15 @@ cr.define('cr.ui.pageManager', function() {
PageManager.onPageVisibilityChanged(this);
} else {
// Kick change events for text fields.
- if (pageDiv.contains(document.activeElement))
+ if (pageDiv.contains(document.activeElement)) {
document.activeElement.blur();
+ }
container.classList.add('transparent');
}
- if (loading)
+ if (loading) {
this.fadeCompleted_();
+ }
},
/**
@@ -291,8 +297,9 @@ cr.define('cr.ui.pageManager', function() {
this.pageDiv.hidden = true;
this.container.hidden = true;
- if (this.parentPage)
+ if (this.parentPage) {
this.parentPage.pageDiv.parentElement.removeAttribute('aria-hidden');
+ }
PageManager.onPageVisibilityChanged(this);
}
diff --git a/chromium/ui/webui/resources/js/cr/ui/page_manager/page_manager.js b/chromium/ui/webui/resources/js/cr/ui/page_manager/page_manager.js
index 00d92c3fa0e..fa9a0d260d9 100644
--- a/chromium/ui/webui/resources/js/cr/ui/page_manager/page_manager.js
+++ b/chromium/ui/webui/resources/js/cr/ui/page_manager/page_manager.js
@@ -11,7 +11,7 @@ cr.define('cr.ui.pageManager', function() {
* can call into PageManager to open a particular overlay or cancel an
* existing overlay.
*/
- var PageManager = {
+ const PageManager = {
/**
* True if page is served from a dialog.
* @type {boolean}
@@ -61,10 +61,10 @@ cr.define('cr.ui.pageManager', function() {
this.handleScroll_();
// Shake the dialog if the user clicks outside the dialog bounds.
- var containers = /** @type {!NodeList<!HTMLElement>} */ (
+ const containers = /** @type {!NodeList<!HTMLElement>} */ (
document.querySelectorAll('body > .overlay'));
- for (var i = 0; i < containers.length; i++) {
- var overlay = containers[i];
+ for (let i = 0; i < containers.length; i++) {
+ const overlay = containers[i];
cr.ui.overlay.setupOverlay(overlay);
overlay.addEventListener(
'cancelOverlay', this.cancelOverlay.bind(this));
@@ -109,7 +109,7 @@ cr.define('cr.ui.pageManager', function() {
}
// Sanity check.
- for (var i = 0; i < associatedControls.length; ++i) {
+ for (let i = 0; i < associatedControls.length; ++i) {
assert(associatedControls[i], 'Invalid element passed.');
}
}
@@ -150,9 +150,9 @@ cr.define('cr.ui.pageManager', function() {
this.hideBubble();
// Find the currently visible root-level page.
- var rootPage = null;
- for (var name in this.registeredPages) {
- var page = this.registeredPages[name];
+ let rootPage = null;
+ for (const name in this.registeredPages) {
+ const page = this.registeredPages[name];
if (page.visible && !page.parentPage) {
rootPage = page;
break;
@@ -160,13 +160,14 @@ cr.define('cr.ui.pageManager', function() {
}
// Find the target page.
- var targetPage = this.registeredPages[pageName.toLowerCase()];
+ let targetPage = this.registeredPages[pageName.toLowerCase()];
if (!targetPage || !targetPage.canShowPage()) {
// If it's not a page, try it as an overlay.
- var hash = opt_propertyBag.hash || '';
+ const hash = opt_propertyBag.hash || '';
if (!targetPage && this.showOverlay_(pageName, hash, rootPage)) {
- if (opt_updateHistory)
+ if (opt_updateHistory) {
this.updateHistoryState_(!!opt_propertyBag.replaceState);
+ }
this.updateTitle_();
return;
}
@@ -174,18 +175,19 @@ cr.define('cr.ui.pageManager', function() {
}
pageName = targetPage.name.toLowerCase();
- var targetPageWasVisible = targetPage.visible;
+ const targetPageWasVisible = targetPage.visible;
// Determine if the root page is 'sticky', meaning that it
// shouldn't change when showing an overlay. This can happen for special
// pages like Search.
- var isRootPageLocked =
+ const isRootPageLocked =
rootPage && rootPage.sticky && targetPage.parentPage;
// Notify pages if they will be hidden.
this.forEachPage_(!isRootPageLocked, function(page) {
- if (page.name != pageName && !this.isAncestorOfPage(page, targetPage))
+ if (page.name != pageName && !this.isAncestorOfPage(page, targetPage)) {
page.willHidePage();
+ }
});
// Update the page's hash.
@@ -198,8 +200,9 @@ cr.define('cr.ui.pageManager', function() {
});
// Update the history and current location.
- if (opt_updateHistory)
+ if (opt_updateHistory) {
this.updateHistoryState_(!!opt_propertyBag.replaceState);
+ }
// Update focus if any other control was focused on the previous page,
// or the previous page is not known.
@@ -219,8 +222,9 @@ cr.define('cr.ui.pageManager', function() {
// If the target page was already visible, notify it that its hash
// changed externally.
- if (targetPageWasVisible)
+ if (targetPageWasVisible) {
targetPage.didChangeHash();
+ }
// Update the document title. Do this after didShowPage was called, in
// case a page decides to change its title.
@@ -232,9 +236,10 @@ cr.define('cr.ui.pageManager', function() {
* @return {string} Name of the page specified by the current path.
*/
getPageNameFromPath: function() {
- var path = location.pathname;
- if (path.length <= 1)
+ const path = location.pathname;
+ if (path.length <= 1) {
return this.defaultPage_.name;
+ }
// Skip starting slash and remove trailing slash (if any).
return path.slice(1).replace(/\/$/, '');
@@ -246,8 +251,8 @@ cr.define('cr.ui.pageManager', function() {
* @return {number} How far down this page is from the root page.
*/
getNestingLevel: function(page) {
- var level = 0;
- var parent = page.parentPage;
+ let level = 0;
+ let parent = page.parentPage;
while (parent) {
level++;
parent = parent.parentPage;
@@ -264,10 +269,11 @@ cr.define('cr.ui.pageManager', function() {
* |potentialAncestor|.
*/
isAncestorOfPage: function(potentialAncestor, potentialDescendent) {
- var parent = potentialDescendent.parentPage;
+ let parent = potentialDescendent.parentPage;
while (parent) {
- if (parent == potentialAncestor)
+ if (parent == potentialAncestor) {
return true;
+ }
parent = parent.parentPage;
}
return false;
@@ -293,11 +299,13 @@ cr.define('cr.ui.pageManager', function() {
onPageVisibilityChanged: function(page) {
this.updateRootPageFreezeState();
- for (var i = 0; i < this.observers_.length; ++i)
+ for (let i = 0; i < this.observers_.length; ++i) {
this.observers_[i].onPageVisibilityChanged(page);
+ }
- if (!page.visible && this.isTopLevelOverlay(page))
+ if (!page.visible && this.isTopLevelOverlay(page)) {
this.updateScrollPosition_();
+ }
},
/**
@@ -306,8 +314,9 @@ cr.define('cr.ui.pageManager', function() {
* @param {cr.ui.pageManager.Page} page The page whose hash has changed.
*/
onPageHashChanged: function(page) {
- if (page == this.getTopmostVisiblePage())
+ if (page == this.getTopmostVisiblePage()) {
this.updateHistoryState_(false);
+ }
},
/**
@@ -325,9 +334,10 @@ cr.define('cr.ui.pageManager', function() {
* overlay.
*/
closeOverlay: function() {
- var overlay = this.getVisibleOverlay_();
- if (!overlay)
+ const overlay = this.getVisibleOverlay_();
+ if (!overlay) {
return;
+ }
overlay.visible = false;
overlay.didClosePage();
@@ -353,9 +363,10 @@ cr.define('cr.ui.pageManager', function() {
cancelOverlay: function() {
// Blur the active element to ensure any changed pref value is saved.
document.activeElement.blur();
- var overlay = this.getVisibleOverlay_();
- if (!overlay)
+ const overlay = this.getVisibleOverlay_();
+ if (!overlay) {
return;
+ }
// Let the overlay handle the <Esc> if it wants to.
if (overlay.handleCancel) {
overlay.handleCancel();
@@ -378,7 +389,7 @@ cr.define('cr.ui.pageManager', function() {
showBubble: function(content, target, domSibling, location) {
this.hideBubble();
- var bubble = new cr.ui.AutoCloseBubble;
+ const bubble = new cr.ui.AutoCloseBubble;
bubble.anchorNode = target;
bubble.domSibling = domSibling;
bubble.arrowLocation = location;
@@ -391,8 +402,9 @@ cr.define('cr.ui.pageManager', function() {
* Hides the currently visible bubble, if any.
*/
hideBubble: function() {
- if (this.bubble_)
+ if (this.bubble_) {
this.bubble_.hide();
+ }
},
/**
@@ -400,7 +412,7 @@ cr.define('cr.ui.pageManager', function() {
* @return {cr.ui.AutoCloseBubble} The bubble currently being shown.
*/
getVisibleBubble: function() {
- var bubble = this.bubble_;
+ const bubble = this.bubble_;
return bubble && !bubble.hidden ? bubble : null;
},
@@ -411,9 +423,9 @@ cr.define('cr.ui.pageManager', function() {
* @param {Object} data State data pushed into history.
*/
setState: function(pageName, hash, data) {
- var currentOverlay = this.getVisibleOverlay_();
- var lowercaseName = pageName.toLowerCase();
- var newPage = this.registeredPages[lowercaseName] ||
+ const currentOverlay = this.getVisibleOverlay_();
+ const lowercaseName = pageName.toLowerCase();
+ const newPage = this.registeredPages[lowercaseName] ||
this.registeredOverlayPages[lowercaseName] || this.defaultPage_;
if (currentOverlay && !this.isAncestorOfPage(currentOverlay, newPage)) {
currentOverlay.visible = false;
@@ -436,9 +448,10 @@ cr.define('cr.ui.pageManager', function() {
* will be closed.
*/
willClose: function() {
- var overlay = this.getVisibleOverlay_();
- if (overlay)
+ const overlay = this.getVisibleOverlay_();
+ if (overlay) {
overlay.didClosePage();
+ }
},
/**
@@ -446,9 +459,10 @@ cr.define('cr.ui.pageManager', function() {
* current page stack.
*/
updateRootPageFreezeState: function() {
- var topPage = this.getTopmostVisiblePage();
- if (topPage)
+ const topPage = this.getTopmostVisiblePage();
+ if (topPage) {
this.setRootPageFrozen_(topPage.isOverlay);
+ }
},
/**
@@ -477,16 +491,19 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
showOverlay_: function(overlayName, hash, rootPage) {
- var overlay = this.registeredOverlayPages[overlayName.toLowerCase()];
- if (!overlay || !overlay.canShowPage())
+ const overlay = this.registeredOverlayPages[overlayName.toLowerCase()];
+ if (!overlay || !overlay.canShowPage()) {
return false;
+ }
- var focusOutlineManager = cr.ui.FocusOutlineManager.forDocument(document);
+ const focusOutlineManager =
+ cr.ui.FocusOutlineManager.forDocument(document);
// Save the currently focused element in the page for restoration later.
- var currentPage = this.getTopmostVisiblePage();
- if (currentPage && focusOutlineManager.visible)
+ const currentPage = this.getTopmostVisiblePage();
+ if (currentPage && focusOutlineManager.visible) {
currentPage.lastFocusedElement = document.activeElement;
+ }
if ((!rootPage || !rootPage.sticky) && overlay.parentPage &&
!overlay.parentPage.visible) {
@@ -501,14 +518,16 @@ cr.define('cr.ui.pageManager', function() {
overlay.didChangeHash();
}
- if (focusOutlineManager.visible)
+ if (focusOutlineManager.visible) {
overlay.focus();
+ }
- if (!overlay.pageDiv.contains(document.activeElement))
+ if (!overlay.pageDiv.contains(document.activeElement)) {
document.activeElement.blur();
+ }
if ($('search-field') && $('search-field').value == '') {
- var section = overlay.associatedSection;
+ const section = overlay.associatedSection;
if (section) {
/** @suppress {checkTypes|checkVars} */
(function() {
@@ -535,14 +554,16 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
getVisibleOverlay_: function() {
- var topmostPage = null;
- for (var name in this.registeredOverlayPages) {
- var page = this.registeredOverlayPages[name];
- if (!page.visible)
+ let topmostPage = null;
+ for (const name in this.registeredOverlayPages) {
+ const page = this.registeredOverlayPages[name];
+ if (!page.visible) {
continue;
+ }
- if (page.alwaysOnTop)
+ if (page.alwaysOnTop) {
return page;
+ }
if (!topmostPage ||
this.getNestingLevel(page) > this.getNestingLevel(topmostPage)) {
@@ -559,10 +580,11 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
getTopmostVisibleNonOverlayPage_: function() {
- for (var name in this.registeredPages) {
- var page = this.registeredPages[name];
- if (page.visible)
+ for (const name in this.registeredPages) {
+ const page = this.registeredPages[name];
+ if (page.visible) {
return page;
+ }
}
return null;
@@ -575,8 +597,8 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
updateScrollPosition_: function() {
- var container = $('page-container');
- var scrollTop = container.oldScrollTop || 0;
+ const container = $('page-container');
+ const scrollTop = container.oldScrollTop || 0;
container.oldScrollTop = undefined;
window.scroll(scrollLeftForDocument(document), scrollTop);
},
@@ -587,10 +609,10 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
updateTitle_: function() {
- var page = this.getTopmostVisiblePage();
+ let page = this.getTopmostVisiblePage();
while (page) {
if (page.title) {
- for (var i = 0; i < this.observers_.length; ++i) {
+ for (let i = 0; i < this.observers_.length; ++i) {
this.observers_[i].updateTitle(page.title);
}
return;
@@ -607,11 +629,12 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
updateHistoryState_: function(replace) {
- if (this.isDialog)
+ if (this.isDialog) {
return;
+ }
- var page = this.getTopmostVisiblePage();
- var path = window.location.pathname + window.location.hash;
+ const page = this.getTopmostVisiblePage();
+ let path = window.location.pathname + window.location.hash;
if (path) {
// Remove trailing slash.
path = path.slice(1).replace(/\/(?:#|$)/, '');
@@ -619,11 +642,12 @@ cr.define('cr.ui.pageManager', function() {
// If the page is already in history (the user may have clicked the same
// link twice, or this is the initial load), do nothing.
- var newPath = (page == this.defaultPage_ ? '' : page.name) + page.hash;
- if (path == newPath)
+ const newPath = (page == this.defaultPage_ ? '' : page.name) + page.hash;
+ if (path == newPath) {
return;
+ }
- for (var i = 0; i < this.observers_.length; ++i) {
+ for (let i = 0; i < this.observers_.length; ++i) {
this.observers_[i].updateHistory(newPath, replace);
}
},
@@ -633,13 +657,15 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
restoreLastFocusedElement_: function() {
- var currentPage = this.getTopmostVisiblePage();
+ const currentPage = this.getTopmostVisiblePage();
- if (!currentPage.lastFocusedElement)
+ if (!currentPage.lastFocusedElement) {
return;
+ }
- if (cr.ui.FocusOutlineManager.forDocument(document).visible)
+ if (cr.ui.FocusOutlineManager.forDocument(document).visible) {
currentPage.lastFocusedElement.focus();
+ }
currentPage.lastFocusedElement = null;
},
@@ -652,8 +678,9 @@ cr.define('cr.ui.pageManager', function() {
*/
findSectionForNode_: function(node) {
while (node = node.parentNode) {
- if (node.nodeName == 'SECTION')
+ if (node.nodeName == 'SECTION') {
return node;
+ }
}
return null;
},
@@ -664,16 +691,17 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
setRootPageFrozen_: function(freeze) {
- var container = $('page-container');
- if (container.classList.contains('frozen') == freeze)
+ const container = $('page-container');
+ if (container.classList.contains('frozen') == freeze) {
return;
+ }
if (freeze) {
// Lock the width, since auto width computation may change.
container.style.width = window.getComputedStyle(container).width;
container.oldScrollTop = scrollTopForDocument(document);
container.classList.add('frozen');
- var verticalPosition =
+ const verticalPosition =
container.getBoundingClientRect().top - container.oldScrollTop;
container.style.top = verticalPosition + 'px';
this.updateFrozenElementHorizontalPosition_(container);
@@ -700,9 +728,10 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
updateAllFrozenElementPositions_: function() {
- var frozenElements = document.querySelectorAll('.frozen');
- for (var i = 0; i < frozenElements.length; i++)
+ const frozenElements = document.querySelectorAll('.frozen');
+ for (let i = 0; i < frozenElements.length; i++) {
this.updateFrozenElementHorizontalPosition_(frozenElements[i]);
+ }
},
/**
@@ -714,7 +743,7 @@ cr.define('cr.ui.pageManager', function() {
if (isRTL()) {
e.style.right = this.horizontalOffset + 'px';
} else {
- var scrollLeft = scrollLeftForDocument(document);
+ const scrollLeft = scrollLeftForDocument(document);
e.style.left = this.horizontalOffset - scrollLeft + 'px';
}
},
@@ -727,9 +756,10 @@ cr.define('cr.ui.pageManager', function() {
* @private
*/
forEachPage_: function(includeRootPages, callback) {
- var pageNames = Object.keys(this.registeredOverlayPages);
- if (includeRootPages)
+ let pageNames = Object.keys(this.registeredOverlayPages);
+ if (includeRootPages) {
pageNames = Object.keys(this.registeredPages).concat(pageNames);
+ }
pageNames.forEach(function(name) {
callback.call(
@@ -741,7 +771,7 @@ cr.define('cr.ui.pageManager', function() {
/**
* An observer of PageManager.
- * @interface
+ * @constructor
*/
PageManager.Observer = function() {};
diff --git a/chromium/ui/webui/resources/js/cr/ui/position_util.js b/chromium/ui/webui/resources/js/cr/ui/position_util.js
index dc7ea034373..edca43d023f 100644
--- a/chromium/ui/webui/resources/js/cr/ui/position_util.js
+++ b/chromium/ui/webui/resources/js/cr/ui/position_util.js
@@ -47,7 +47,7 @@ cr.ui.AnchorType = {
cr.define('cr.ui', function() {
/** @const */
- var AnchorType = cr.ui.AnchorType;
+ const AnchorType = cr.ui.AnchorType;
/**
* Helper function for positionPopupAroundElement and positionPopupAroundRect.
@@ -59,11 +59,11 @@ cr.define('cr.ui', function() {
*/
function positionPopupAroundRect(
anchorRect, popupElement, type, opt_invertLeftRight) {
- var popupRect = popupElement.getBoundingClientRect();
- var availRect;
- var ownerDoc = popupElement.ownerDocument;
- var cs = ownerDoc.defaultView.getComputedStyle(popupElement);
- var docElement = ownerDoc.documentElement;
+ const popupRect = popupElement.getBoundingClientRect();
+ let availRect;
+ const ownerDoc = popupElement.ownerDocument;
+ const cs = ownerDoc.defaultView.getComputedStyle(popupElement);
+ const docElement = ownerDoc.documentElement;
if (cs.position == 'fixed') {
// For 'fixed' positioned popups, the available rectangle should be based
@@ -80,15 +80,17 @@ cr.define('cr.ui', function() {
availRect = popupElement.offsetParent.getBoundingClientRect();
}
- if (cs.direction == 'rtl')
+ if (cs.direction == 'rtl') {
opt_invertLeftRight = !opt_invertLeftRight;
+ }
// Flip BEFORE, AFTER based on alignment.
if (opt_invertLeftRight) {
- if (type == AnchorType.BEFORE)
+ if (type == AnchorType.BEFORE) {
type = AnchorType.AFTER;
- else if (type == AnchorType.AFTER)
+ } else if (type == AnchorType.AFTER) {
type = AnchorType.BEFORE;
+ }
}
// Flip type based on available size
@@ -120,35 +122,39 @@ cr.define('cr.ui', function() {
}
// flipping done
- var style = popupElement.style;
+ const style = popupElement.style;
// Reset all directions.
style.left = style.right = style.top = style.bottom = 'auto';
// Primary direction
switch (type) {
case AnchorType.BELOW:
- if (anchorRect.bottom + popupRect.height <= availRect.height)
+ if (anchorRect.bottom + popupRect.height <= availRect.height) {
style.top = anchorRect.bottom + 'px';
- else
+ } else {
style.bottom = '0';
+ }
break;
case AnchorType.ABOVE:
- if (availRect.height - anchorRect.top >= 0)
+ if (availRect.height - anchorRect.top >= 0) {
style.bottom = availRect.height - anchorRect.top + 'px';
- else
+ } else {
style.top = '0';
+ }
break;
case AnchorType.AFTER:
- if (anchorRect.right + popupRect.width <= availRect.width)
+ if (anchorRect.right + popupRect.width <= availRect.width) {
style.left = anchorRect.right + 'px';
- else
+ } else {
style.right = '0';
+ }
break;
case AnchorType.BEFORE:
- if (availRect.width - anchorRect.left >= 0)
+ if (availRect.width - anchorRect.left >= 0) {
style.right = availRect.width - anchorRect.left + 'px';
- else
+ } else {
style.left = '0';
+ }
break;
}
@@ -216,7 +222,7 @@ cr.define('cr.ui', function() {
*/
function positionPopupAroundElement(
anchorElement, popupElement, type, opt_invertLeftRight) {
- var anchorRect = anchorElement.getBoundingClientRect();
+ const anchorRect = anchorElement.getBoundingClientRect();
positionPopupAroundRect(
anchorRect, popupElement, type, !!opt_invertLeftRight);
}
@@ -229,9 +235,9 @@ cr.define('cr.ui', function() {
* @param {cr.ui.AnchorType=} opt_anchorType The type of anchoring we want.
*/
function positionPopupAtPoint(x, y, popupElement, opt_anchorType) {
- var rect = {left: x, top: y, width: 0, height: 0, right: x, bottom: y};
+ const rect = {left: x, top: y, width: 0, height: 0, right: x, bottom: y};
- var anchorType = opt_anchorType || AnchorType.BELOW;
+ const anchorType = opt_anchorType || AnchorType.BELOW;
positionPopupAroundRect(rect, popupElement, anchorType);
}
diff --git a/chromium/ui/webui/resources/js/cr/ui/repeating_button.js b/chromium/ui/webui/resources/js/cr/ui/repeating_button.js
index d125afdeb95..427d45f1542 100644
--- a/chromium/ui/webui/resources/js/cr/ui/repeating_button.js
+++ b/chromium/ui/webui/resources/js/cr/ui/repeating_button.js
@@ -10,7 +10,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLButtonElement}
*/
- var RepeatingButton = cr.ui.define('button');
+ const RepeatingButton = cr.ui.define('button');
/**
* DOM Events that may be fired by the Repeating button.
@@ -94,8 +94,8 @@ cr.define('cr.ui', function() {
// TODO(kevers): Consider adding a common location for picking up the
// initial delay and repeat interval.
this.buttonHeld_();
- var self = this;
- var armRepeaterCallback = function() {
+ const self = this;
+ const armRepeaterCallback = function() {
// In the event of a click/tap operation, this button has already been
// released by the time this timeout triggers. Test to ensure that the
// button is still being held (i.e. clearTimeout has not been called).
diff --git a/chromium/ui/webui/resources/js/cr/ui/splitter.js b/chromium/ui/webui/resources/js/cr/ui/splitter.js
index 4c97d691413..00d1c867e9d 100644
--- a/chromium/ui/webui/resources/js/cr/ui/splitter.js
+++ b/chromium/ui/webui/resources/js/cr/ui/splitter.js
@@ -41,13 +41,13 @@ cr.define('cr.ui', function() {
* @return {number} The zoom factor of the document.
*/
function getZoomFactor(doc) {
- var dummyElement = doc.createElement('div');
+ const dummyElement = doc.createElement('div');
dummyElement.style.cssText = 'position:absolute;width:100px;height:100px;' +
'top:-1000px;overflow:hidden';
doc.body.appendChild(dummyElement);
- var cs = doc.defaultView.getComputedStyle(dummyElement);
- var rect = dummyElement.getBoundingClientRect();
- var zoomFactor = parseFloat(cs.width) / 100;
+ const cs = doc.defaultView.getComputedStyle(dummyElement);
+ const rect = dummyElement.getBoundingClientRect();
+ const zoomFactor = parseFloat(cs.width) / 100;
doc.body.removeChild(dummyElement);
return zoomFactor;
}
@@ -58,7 +58,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLDivElement}
*/
- var Splitter = cr.ui.define('div');
+ const Splitter = cr.ui.define('div');
Splitter.prototype = {
__proto__: HTMLDivElement.prototype,
@@ -95,7 +95,7 @@ cr.define('cr.ui', function() {
this.endDrag_();
}
if (isTouchEvent) {
- var endDragBound = this.endDrag_.bind(this);
+ const endDragBound = this.endDrag_.bind(this);
this.handlers_ = {
'touchmove': this.handleTouchMove_.bind(this),
'touchend': endDragBound,
@@ -111,11 +111,11 @@ cr.define('cr.ui', function() {
};
}
- var doc = this.ownerDocument;
+ const doc = this.ownerDocument;
// Use capturing events on the document to get events when the mouse
// leaves the document.
- for (var eventType in this.handlers_) {
+ for (const eventType in this.handlers_) {
doc.addEventListener(eventType, this.handlers_[eventType], true);
}
@@ -129,8 +129,8 @@ cr.define('cr.ui', function() {
* @private
*/
endDrag_: function() {
- var doc = this.ownerDocument;
- for (var eventType in this.handlers_) {
+ const doc = this.ownerDocument;
+ for (const eventType in this.handlers_) {
doc.removeEventListener(eventType, this.handlers_[eventType], true);
}
this.handlers_ = null;
@@ -163,8 +163,9 @@ cr.define('cr.ui', function() {
*/
handleMouseDown_: function(e) {
e = /** @type {!MouseEvent} */ (e);
- if (e.button)
+ if (e.button) {
return;
+ }
this.startDrag(e.clientX, false);
// Default action is to start selection and to move focus.
e.preventDefault();
@@ -198,8 +199,9 @@ cr.define('cr.ui', function() {
* @param {!TouchEvent} e The touch event.
*/
handleTouchMove_: function(e) {
- if (e.touches.length == 1)
+ if (e.touches.length == 1) {
this.handleMove_(e.touches[0].clientX);
+ }
},
/**
@@ -209,11 +211,11 @@ cr.define('cr.ui', function() {
* @private
*/
handleMove_: function(clientX) {
- var rtl =
+ const rtl =
this.ownerDocument.defaultView.getComputedStyle(this).direction ==
'rtl';
- var dirMultiplier = rtl ? -1 : 1;
- var deltaX = dirMultiplier * (clientX - this.startX_);
+ const dirMultiplier = rtl ? -1 : 1;
+ const deltaX = dirMultiplier * (clientX - this.startX_);
this.handleSplitterDragMove(deltaX);
},
@@ -234,8 +236,8 @@ cr.define('cr.ui', function() {
// Use the computed width style as the base so that we can ignore what
// box sizing the element has. Add the difference between offset and
// client widths to account for any scrollbars.
- var targetElement = this.getResizeTarget_();
- var doc = targetElement.ownerDocument;
+ const targetElement = this.getResizeTarget_();
+ const doc = targetElement.ownerDocument;
this.startWidth_ =
parseFloat(doc.defaultView.getComputedStyle(targetElement).width) +
targetElement.offsetWidth - targetElement.clientWidth;
@@ -248,8 +250,8 @@ cr.define('cr.ui', function() {
* @param {number} deltaX The change of splitter horizontal position.
*/
handleSplitterDragMove: function(deltaX) {
- var targetElement = this.getResizeTarget_();
- var newWidth = this.startWidth_ + this.calcDeltaX_(deltaX);
+ const targetElement = this.getResizeTarget_();
+ const newWidth = this.startWidth_ + this.calcDeltaX_(deltaX);
targetElement.style.width = newWidth + 'px';
cr.dispatchSimpleEvent(this, 'dragmove');
},
@@ -260,12 +262,13 @@ cr.define('cr.ui', function() {
*/
handleSplitterDragEnd: function() {
// Check if the size changed.
- var targetElement = this.getResizeTarget_();
- var doc = targetElement.ownerDocument;
- var computedWidth =
+ const targetElement = this.getResizeTarget_();
+ const doc = targetElement.ownerDocument;
+ const computedWidth =
parseFloat(doc.defaultView.getComputedStyle(targetElement).width);
- if (this.startWidth_ != computedWidth)
+ if (this.startWidth_ != computedWidth) {
cr.dispatchSimpleEvent(this, 'resize');
+ }
this.classList.remove('splitter-active');
},
diff --git a/chromium/ui/webui/resources/js/cr/ui/store.js b/chromium/ui/webui/resources/js/cr/ui/store.js
new file mode 100644
index 00000000000..3833498b7ee
--- /dev/null
+++ b/chromium/ui/webui/resources/js/cr/ui/store.js
@@ -0,0 +1,167 @@
+// 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.
+
+cr.define('cr.ui', function() {
+ /** @typedef {{name: string}} */
+ let Action;
+
+ /** @typedef {function(function(?cr.ui.Action))} */
+ let DeferredAction;
+
+ /**
+ * @interface
+ * @template T
+ */
+ class StoreObserver {
+ /** @param {!T} newState */
+ onStateChanged(newState) {}
+ }
+
+ /**
+ * A generic datastore for the state of a page, where the state is publicly
+ * readable but can only be modified by dispatching an Action.
+ * The Store should be extended by specifying T, the page state type
+ * associated with the store.
+ * @template T
+ */
+ class Store {
+ /**
+ * @param {T} emptyState
+ * @param {function(T, cr.ui.Action):T} reducer
+ */
+ constructor(emptyState, reducer) {
+ /** @type {!T} */
+ this.data = emptyState;
+ /** @type {function(T, cr.ui.Action):T} */
+ this.reducer_ = reducer;
+ /** @type {boolean} */
+ this.initialized_ = false;
+ /** @type {!Array<cr.ui.DeferredAction>} */
+ this.queuedActions_ = [];
+ /** @type {!Array<!cr.ui.StoreObserver>} */
+ this.observers_ = [];
+ /** @private {boolean} */
+ this.batchMode_ = false;
+ }
+
+ /**
+ * @param {!T} initialState
+ */
+ init(initialState) {
+ this.data = initialState;
+
+ this.queuedActions_.forEach((action) => {
+ this.dispatchInternal_(action);
+ });
+
+ this.initialized_ = true;
+ this.notifyObservers_(this.data);
+ }
+
+ /** @return {boolean} */
+ isInitialized() {
+ return this.initialized_;
+ }
+
+ /** @param {!cr.ui.StoreObserver} observer */
+ addObserver(observer) {
+ this.observers_.push(observer);
+ }
+
+ /** @param {!cr.ui.StoreObserver} observer */
+ removeObserver(observer) {
+ const index = this.observers_.indexOf(observer);
+ this.observers_.splice(index, 1);
+ }
+
+ /**
+ * Begin a batch update to store data, which will disable updates to the
+ * UI until `endBatchUpdate` is called. This is useful when a single UI
+ * operation is likely to cause many sequential model updates (eg, deleting
+ * 100 bookmarks).
+ */
+ beginBatchUpdate() {
+ this.batchMode_ = true;
+ }
+
+ /**
+ * End a batch update to the store data, notifying the UI of any changes
+ * which occurred while batch mode was enabled.
+ */
+ endBatchUpdate() {
+ this.batchMode_ = false;
+ this.notifyObservers_(this.data);
+ }
+
+ /**
+ * Handles a 'deferred' action, which can asynchronously dispatch actions
+ * to the Store in order to reach a new UI state. DeferredActions have the
+ * form `dispatchAsync(function(dispatch) { ... })`). Inside that function,
+ * the |dispatch| callback can be called asynchronously to dispatch Actions
+ * directly to the Store.
+ * @param {cr.ui.DeferredAction} action
+ */
+ dispatchAsync(action) {
+ if (!this.initialized_) {
+ this.queuedActions_.push(action);
+ return;
+ }
+ this.dispatchInternal_(action);
+ }
+
+ /**
+ * Transition to a new UI state based on the supplied |action|, and notify
+ * observers of the change. If the Store has not yet been initialized, the
+ * action will be queued and performed upon initialization.
+ * @param {?cr.ui.Action} action
+ */
+ dispatch(action) {
+ this.dispatchAsync(function(dispatch) {
+ dispatch(action);
+ });
+ }
+
+ /**
+ * @param {cr.ui.DeferredAction} action
+ */
+ dispatchInternal_(action) {
+ action(this.reduce_.bind(this));
+ }
+
+ /**
+ * @param {?cr.ui.Action} action
+ * @private
+ */
+ reduce_(action) {
+ if (!action) {
+ return;
+ }
+
+ this.data = this.reducer_(this.data, action);
+
+ // Batch notifications until after all initialization queuedActions are
+ // resolved.
+ if (this.isInitialized() && !this.batchMode_) {
+ this.notifyObservers_(this.data);
+ }
+ }
+
+ /**
+ * @param {!T} state
+ * @private
+ */
+ notifyObservers_(state) {
+ this.observers_.forEach(function(o) {
+ o.onStateChanged(state);
+ });
+ }
+ }
+
+ return {
+ Action: Action,
+ DeferredAction: DeferredAction,
+ Store: Store,
+ StoreObserver: StoreObserver,
+ };
+});
diff --git a/chromium/ui/webui/resources/js/cr/ui/store_client.js b/chromium/ui/webui/resources/js/cr/ui/store_client.js
new file mode 100644
index 00000000000..adb1ef91976
--- /dev/null
+++ b/chromium/ui/webui/resources/js/cr/ui/store_client.js
@@ -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.
+
+cr.define('cr.ui', function() {
+ /**
+ * StoreClient is a Polymer behavior which ties front-end elements to
+ * back-end data from an associated Store. An element using this behavior
+ * can use the watch method to tie one of its properties to a specific piece
+ * of data from the Store.
+ *
+ * This StoreClient is generic, and needs to be combined with a
+ * page-specific implementation, as in
+ * chrome/browser/resources/bookmarks/store_client.js.
+ * This implementation should override the watch, getState and getStore
+ * methods.
+ *
+ * These methods need to be overridden to allow type-checking on them,
+ * since they all use the page state type associated with the specific page,
+ * and templates cannot be applied to Polymer behaviors. Polymer 2 Mixins
+ * may solve these type-checking problems.
+ *
+ * @polymerBehavior
+ */
+ const StoreClient = {
+ created: function() {
+ /**
+ * @type {!Array<{
+ * localProperty: string,
+ * valueGetter: function(!Object)
+ * }>}
+ */
+ this.watches_ = [];
+ },
+
+ attached: function() {
+ this.getStore().addObserver(this);
+ },
+
+ detached: function() {
+ this.getStore().removeObserver(this);
+ },
+
+ /**
+ * Watches a particular part of the state tree, updating |localProperty|
+ * to the return value of |valueGetter| whenever the state changes. Eg, to
+ * keep |this.item| updated with the value of a node:
+ * watch('item', (state) => state.nodes[this.itemId]);
+ *
+ * Note that object identity is used to determine if the value has changed
+ * before updating the UI, rather than Polymer-style deep equality. If the
+ * getter function returns |undefined|, no changes will propagate to the UI.
+ *
+ * @param {string} localProperty
+ * @param {function(!Object)} valueGetter
+ */
+ watch_: function(localProperty, valueGetter) {
+ this.watches_.push({
+ localProperty: localProperty,
+ valueGetter: valueGetter,
+ });
+ },
+
+ /**
+ * Helper to dispatch an action to the store, which will update the store
+ * data and then (possibly) flow through to the UI.
+ * @param {?cr.ui.Action} action
+ */
+ dispatch: function(action) {
+ this.getStore().dispatch(action);
+ },
+
+ /**
+ * Helper to dispatch a DeferredAction to the store, which will
+ * asynchronously perform updates to the store data and UI.
+ * @param {cr.ui.DeferredAction} action
+ */
+ dispatchAsync: function(action) {
+ this.getStore().dispatchAsync(action);
+ },
+
+ /** @param {string} newState */
+ onStateChanged: function(newState) {
+ this.watches_.forEach((watch) => {
+ const oldValue = this[watch.localProperty];
+ const newValue = watch.valueGetter(newState);
+
+ // Avoid poking Polymer unless something has actually changed. Reducers
+ // must return new objects rather than mutating existing objects, so
+ // any real changes will pass through correctly.
+ if (oldValue === newValue || newValue === undefined) {
+ return;
+ }
+
+ this[watch.localProperty] = newValue;
+ });
+ },
+
+ updateFromStore: function() {
+ if (this.getStore().isInitialized()) {
+ this.onStateChanged(this.getStore().data);
+ }
+ },
+
+ /**
+ * Should be overridden by a function which calls the private watch_
+ * with the given arguments. Needs to be overridden to allow
+ * type-checking on the valueGetter parameter.
+ */
+ watch: function(localProperty, valueGetter) {
+ assertNotReached();
+ },
+
+ /**
+ * Should be overridden by a function which returns the data from the
+ * associated Store. Needs to be overridden to allow type-checking on the
+ * return value, which will be a page state type specific to each page.
+ */
+ getState: function() {
+ assertNotReached();
+ },
+
+ /**
+ * Should be overridden by a function which returns the specific Store
+ * instance associated with the StoreClient. Needs to be overridden to
+ * allow type-checking on the return value, which will be a
+ * page-specific subclass of Store.
+ */
+ getStore: function() {
+ assertNotReached();
+ },
+ };
+
+ return {
+ StoreClient: StoreClient,
+ };
+});
diff --git a/chromium/ui/webui/resources/js/cr/ui/table.js b/chromium/ui/webui/resources/js/cr/ui/table.js
index e6763eabf5a..414be136c54 100644
--- a/chromium/ui/webui/resources/js/cr/ui/table.js
+++ b/chromium/ui/webui/resources/js/cr/ui/table.js
@@ -7,12 +7,12 @@
*/
cr.define('cr.ui', function() {
- /** @const */ var ListSelectionModel = cr.ui.ListSelectionModel;
- /** @const */ var ListSelectionController = cr.ui.ListSelectionController;
- /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
- /** @const */ var TableColumnModel = cr.ui.table.TableColumnModel;
- /** @const */ var TableList = cr.ui.table.TableList;
- /** @const */ var TableHeader = cr.ui.table.TableHeader;
+ /** @const */ const ListSelectionModel = cr.ui.ListSelectionModel;
+ /** @const */ const ListSelectionController = cr.ui.ListSelectionController;
+ /** @const */ const ArrayDataModel = cr.ui.ArrayDataModel;
+ /** @const */ const TableColumnModel = cr.ui.table.TableColumnModel;
+ /** @const */ const TableList = cr.ui.table.TableList;
+ /** @const */ const TableHeader = cr.ui.table.TableHeader;
/**
* Creates a new table element.
@@ -20,7 +20,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLDivElement}
*/
- var Table = cr.ui.define('div');
+ const Table = cr.ui.define('div');
Table.prototype = {
__proto__: HTMLDivElement.prototype,
@@ -77,12 +77,14 @@ cr.define('cr.ui', function() {
},
set columnModel(columnModel) {
if (this.columnModel_ != columnModel) {
- if (this.columnModel_)
+ if (this.columnModel_) {
this.columnModel_.removeEventListener('resize', this.boundResize_);
+ }
this.columnModel_ = columnModel;
- if (this.columnModel_)
+ if (this.columnModel_) {
this.columnModel_.addEventListener('resize', this.boundResize_);
+ }
this.list_.invalidate();
this.redraw();
}
@@ -99,8 +101,9 @@ cr.define('cr.ui', function() {
},
set selectionModel(selectionModel) {
if (this.list_.selectionModel != selectionModel) {
- if (this.dataModel)
+ if (this.dataModel) {
selectionModel.adjustLength(this.dataModel.length);
+ }
this.list_.selectionModel = selectionModel;
}
},
@@ -139,16 +142,17 @@ cr.define('cr.ui', function() {
// `This` must not be accessed here, since it may be anything, especially
// not a pointer to this object.
- var cm = table.columnModel;
- var listItem = cr.ui.List.prototype.createItem.call(table.list, '');
+ const cm = table.columnModel;
+ const listItem = cr.ui.List.prototype.createItem.call(table.list, '');
listItem.className = 'table-row';
- for (var i = 0; i < cm.size; i++) {
- var cell = table.ownerDocument.createElement('div');
+ for (let i = 0; i < cm.size; i++) {
+ const cell = table.ownerDocument.createElement('div');
cell.style.width = cm.getWidth(i) + 'px';
cell.className = 'table-row-cell';
- if (cm.isEndAlign(i))
+ if (cm.isEndAlign(i)) {
cell.style.textAlign = 'end';
+ }
cell.hidden = !cm.isVisible(i);
cell.appendChild(
cm.getRenderFunction(i).call(null, dataItem, cm.getId(i), table));
@@ -166,8 +170,9 @@ cr.define('cr.ui', function() {
* function.
*/
setRenderFunction: function(renderFunction) {
- if (renderFunction === this.renderFunction_)
+ if (renderFunction === this.renderFunction_) {
return;
+ }
this.renderFunction_ = renderFunction;
cr.dispatchSimpleEvent(this, 'change');
@@ -292,16 +297,17 @@ cr.define('cr.ui', function() {
* @param {number} i The index of the column to sort by.
*/
sort: function(i) {
- var cm = this.columnModel_;
- var sortStatus = this.list_.dataModel.sortStatus;
+ const cm = this.columnModel_;
+ const sortStatus = this.list_.dataModel.sortStatus;
if (sortStatus.field == cm.getId(i)) {
- var sortDirection = sortStatus.direction == 'desc' ? 'asc' : 'desc';
+ const sortDirection = sortStatus.direction == 'desc' ? 'asc' : 'desc';
this.list_.dataModel.sort(sortStatus.field, sortDirection);
} else {
this.list_.dataModel.sort(cm.getId(i), cm.getDefaultOrder(i));
}
- if (this.selectionModel.selectedIndex == -1)
+ if (this.selectionModel.selectedIndex == -1) {
this.list_.scrollTop = 0;
+ }
},
/**
@@ -329,11 +335,11 @@ cr.define('cr.ui', function() {
// When the blur event happens we do not know who is getting focus so we
// delay this a bit until we know if the new focus node is outside the
// table.
- var table = this;
- var list = this.list_;
- var doc = e.target.ownerDocument;
+ const table = this;
+ const list = this.list_;
+ const doc = e.target.ownerDocument;
window.setTimeout(function() {
- var activeElement = doc.activeElement;
+ const activeElement = doc.activeElement;
if (!table.contains(activeElement)) {
table.hasElementFocus = false;
// Force styles based on hasElementFocus to take effect.
@@ -347,20 +353,20 @@ cr.define('cr.ui', function() {
* @param {number} index Index of the column to adjust width.
*/
fitColumn: function(index) {
- var list = this.list_;
- var listHeight = list.clientHeight;
+ const list = this.list_;
+ const listHeight = list.clientHeight;
- var cm = this.columnModel_;
- var dm = this.dataModel;
- var columnId = cm.getId(index);
- var doc = this.ownerDocument;
- var render = cm.getRenderFunction(index);
- var table = this;
- var MAXIMUM_ROWS_TO_MEASURE = 1000;
+ const cm = this.columnModel_;
+ const dm = this.dataModel;
+ const columnId = cm.getId(index);
+ const doc = this.ownerDocument;
+ const render = cm.getRenderFunction(index);
+ const table = this;
+ const MAXIMUM_ROWS_TO_MEASURE = 1000;
// Create a temporaty list item, put all cells into it and measure its
// width. Then remove the item. It fits "list > *" CSS rules.
- var container = doc.createElement('li');
+ const container = doc.createElement('li');
container.style.display = 'inline-block';
container.style.textAlign = 'start';
// The container will have width of the longest cell.
@@ -369,20 +375,20 @@ cr.define('cr.ui', function() {
// Ensure all needed data available.
dm.prepareSort(columnId, function() {
// Select at most MAXIMUM_ROWS_TO_MEASURE items around visible area.
- var items = list.getItemsInViewPort(list.scrollTop, listHeight);
- var firstIndex = Math.floor(Math.max(
+ const items = list.getItemsInViewPort(list.scrollTop, listHeight);
+ const firstIndex = Math.floor(Math.max(
0, (items.last + items.first - MAXIMUM_ROWS_TO_MEASURE) / 2));
- var lastIndex =
+ const lastIndex =
Math.min(dm.length, firstIndex + MAXIMUM_ROWS_TO_MEASURE);
- for (var i = firstIndex; i < lastIndex; i++) {
- var item = dm.item(i);
- var div = doc.createElement('div');
+ for (let i = firstIndex; i < lastIndex; i++) {
+ const item = dm.item(i);
+ const div = doc.createElement('div');
div.className = 'table-row-cell';
div.appendChild(render(item, columnId, table));
container.appendChild(div);
}
list.appendChild(container);
- var width = parseFloat(window.getComputedStyle(container).width);
+ const width = parseFloat(window.getComputedStyle(container).width);
list.removeChild(container);
cm.setWidth(index, width);
});
diff --git a/chromium/ui/webui/resources/js/cr/ui/table/table_column.js b/chromium/ui/webui/resources/js/cr/ui/table/table_column.js
index 1a5ef2b08de..5def72bb256 100644
--- a/chromium/ui/webui/resources/js/cr/ui/table/table_column.js
+++ b/chromium/ui/webui/resources/js/cr/ui/table/table_column.js
@@ -7,7 +7,7 @@
*/
cr.define('cr.ui.table', function() {
- /** @const */ var EventTarget = cr.EventTarget;
+ /** @const */ const EventTarget = cr.EventTarget;
/**
* A table column that wraps column ids and settings.
@@ -36,7 +36,7 @@ cr.define('cr.ui.table', function() {
* @return {cr.ui.table.TableColumn} Clone of the given column.
*/
clone: function() {
- var tableColumn =
+ const tableColumn =
new TableColumn(this.id_, this.name_, this.width_, this.endAlign_);
tableColumn.renderFunction = this.renderFunction_;
tableColumn.headerRenderFunction = this.headerRenderFunction_;
@@ -55,7 +55,7 @@ cr.define('cr.ui.table', function() {
* @return {HTMLElement} Rendered element.
*/
renderFunction_: function(dataItem, columnId, table) {
- var div = /** @type {HTMLElement} */
+ const div = /** @type {HTMLElement} */
(table.ownerDocument.createElement('div'));
div.textContent = dataItem[columnId];
div.hidden = !this.visible;
diff --git a/chromium/ui/webui/resources/js/cr/ui/table/table_column_model.js b/chromium/ui/webui/resources/js/cr/ui/table/table_column_model.js
index 312f4352033..98a0f860a9b 100644
--- a/chromium/ui/webui/resources/js/cr/ui/table/table_column_model.js
+++ b/chromium/ui/webui/resources/js/cr/ui/table/table_column_model.js
@@ -6,7 +6,7 @@
* @fileoverview This is a table column model
*/
cr.define('cr.ui.table', function() {
- /** @const */ var EventTarget = cr.EventTarget;
+ /** @const */ const EventTarget = cr.EventTarget;
/**
* A table column model that wraps table columns array
@@ -18,12 +18,12 @@ cr.define('cr.ui.table', function() {
*/
function TableColumnModel(tableColumns) {
this.columns_ = [];
- for (var i = 0; i < tableColumns.length; i++) {
+ for (let i = 0; i < tableColumns.length; i++) {
this.columns_.push(tableColumns[i].clone());
}
}
- var MIMIMAL_WIDTH = 10;
+ const MIMIMAL_WIDTH = 10;
TableColumnModel.prototype = {
__proto__: EventTarget.prototype,
@@ -61,10 +61,12 @@ cr.define('cr.ui.table', function() {
* @param {string} name Column name.
*/
setName: function(index, name) {
- if (index < 0 || index >= this.columns_.length)
+ if (index < 0 || index >= this.columns_.length) {
return;
- if (name != this.columns_[index].name)
+ }
+ if (name != this.columns_[index].name) {
return;
+ }
this.columns_[index].name = name;
cr.dispatchSimpleEvent(this, 'change');
@@ -94,19 +96,22 @@ cr.define('cr.ui.table', function() {
* @param {number} width Column width.
*/
setWidth: function(index, width) {
- if (index < 0 || index >= this.columns_.length)
+ if (index < 0 || index >= this.columns_.length) {
return;
+ }
- var column = this.columns_[index];
+ const column = this.columns_[index];
width = Math.max(width, MIMIMAL_WIDTH);
- if (width == column.absoluteWidth)
+ if (width == column.absoluteWidth) {
return;
+ }
column.width = width;
// Dispatch an event if a visible column was resized.
- if (column.visible)
+ if (column.visible) {
cr.dispatchSimpleEvent(this, 'resize');
+ }
},
/**
@@ -125,10 +130,12 @@ cr.define('cr.ui.table', function() {
* Render function.
*/
setRenderFunction: function(index, renderFunction) {
- if (index < 0 || index >= this.columns_.length)
+ if (index < 0 || index >= this.columns_.length) {
return;
- if (renderFunction !== this.columns_[index].renderFunction)
+ }
+ if (renderFunction !== this.columns_[index].renderFunction) {
return;
+ }
this.columns_[index].renderFunction = renderFunction;
cr.dispatchSimpleEvent(this, 'change');
@@ -140,7 +147,7 @@ cr.define('cr.ui.table', function() {
* @param {Element} table Owner table.
*/
renderHeader: function(index, table) {
- var c = this.columns_[index];
+ const c = this.columns_[index];
return c.headerRenderFunction.call(c, table);
},
@@ -149,8 +156,8 @@ cr.define('cr.ui.table', function() {
* @type {number}
*/
get totalWidth() {
- var total = 0;
- for (var i = 0; i < this.size; i++) {
+ let total = 0;
+ for (let i = 0; i < this.size; i++) {
total += this.columns_[i].width;
}
return total;
@@ -160,9 +167,10 @@ cr.define('cr.ui.table', function() {
* Normalizes widths to make their sum 100%.
*/
normalizeWidths: function(contentWidth) {
- if (this.size == 0)
+ if (this.size == 0) {
return;
- var c = this.columns_[0];
+ }
+ const c = this.columns_[0];
c.width = Math.max(10, c.width - this.totalWidth + contentWidth);
},
@@ -181,9 +189,10 @@ cr.define('cr.ui.table', function() {
* @return {number} The index of column with given id or -1 if not found.
*/
indexOf: function(id) {
- for (var i = 0; i < this.size; i++) {
- if (this.getId(i) == id)
+ for (let i = 0; i < this.size; i++) {
+ if (this.getId(i) == id) {
return i;
+ }
}
return -1;
},
@@ -194,16 +203,18 @@ cr.define('cr.ui.table', function() {
* @param {boolean} visible The column visibility.
*/
setVisible: function(index, visible) {
- if (index < 0 || index >= this.columns_.length)
+ if (index < 0 || index >= this.columns_.length) {
return;
+ }
- var column = this.columns_[index];
- if (column.visible == visible)
+ const column = this.columns_[index];
+ if (column.visible == visible) {
return;
+ }
// Changing column visibility alters the width. Save the total width out
// first, then change the column visibility, then relayout the table.
- var contentWidth = this.totalWidth;
+ const contentWidth = this.totalWidth;
column.visible = visible;
this.normalizeWidths(contentWidth);
},
diff --git a/chromium/ui/webui/resources/js/cr/ui/table/table_header.js b/chromium/ui/webui/resources/js/cr/ui/table/table_header.js
index 324c01c15e5..0949cfd3fb9 100644
--- a/chromium/ui/webui/resources/js/cr/ui/table/table_header.js
+++ b/chromium/ui/webui/resources/js/cr/ui/table/table_header.js
@@ -7,7 +7,7 @@
*/
cr.define('cr.ui.table', function() {
- /** @const */ var TableSplitter = cr.ui.TableSplitter;
+ /** @const */ const TableSplitter = cr.ui.TableSplitter;
/**
* Creates a new table header.
@@ -15,7 +15,7 @@ cr.define('cr.ui.table', function() {
* @constructor
* @extends {HTMLDivElement}
*/
- var TableHeader = cr.ui.define('div');
+ const TableHeader = cr.ui.define('div');
TableHeader.prototype = {
__proto__: HTMLDivElement.prototype,
@@ -41,7 +41,7 @@ cr.define('cr.ui.table', function() {
*/
updateWidth: function() {
// Header should not span over the vertical scrollbar of the list.
- var list = this.table_.querySelector('list');
+ const list = this.table_.querySelector('list');
this.headerInner_.style.width = list.clientWidth + 'px';
},
@@ -49,14 +49,14 @@ cr.define('cr.ui.table', function() {
* Resizes columns.
*/
resize: function() {
- var headerCells = this.querySelectorAll('.table-header-cell');
+ const headerCells = this.querySelectorAll('.table-header-cell');
if (this.needsFullRedraw_(headerCells)) {
this.redraw();
return;
}
- var cm = this.table_.columnModel;
- for (var i = 0; i < cm.size; i++) {
+ const cm = this.table_.columnModel;
+ for (let i = 0; i < cm.size; i++) {
headerCells[i].style.width = cm.getWidth(i) + 'px';
}
this.placeSplitters_(this.querySelectorAll('.table-header-splitter'));
@@ -70,19 +70,21 @@ cr.define('cr.ui.table', function() {
endBatchUpdates: function() {
this.batchCount_--;
- if (this.batchCount_ == 0)
+ if (this.batchCount_ == 0) {
this.redraw();
+ }
},
/**
* Redraws table header.
*/
redraw: function() {
- if (this.batchCount_ != 0)
+ if (this.batchCount_ != 0) {
return;
+ }
- var cm = this.table_.columnModel;
- var dm = this.table_.dataModel;
+ const cm = this.table_.columnModel;
+ const dm = this.table_.dataModel;
this.updateWidth();
this.headerInner_.textContent = '';
@@ -91,17 +93,18 @@ cr.define('cr.ui.table', function() {
return;
}
- for (var i = 0; i < cm.size; i++) {
- var cell = this.ownerDocument.createElement('div');
+ for (let i = 0; i < cm.size; i++) {
+ const cell = this.ownerDocument.createElement('div');
cell.style.width = cm.getWidth(i) + 'px';
// Don't display cells for hidden columns. Don't omit the cell
// completely, as it's much simpler if the number of cell elements and
// columns are in sync.
cell.hidden = !cm.isVisible(i);
cell.className = 'table-header-cell';
- if (dm.isSortable(cm.getId(i)))
+ if (dm.isSortable(cm.getId(i))) {
cell.addEventListener(
'click', this.createSortFunction_(i).bind(this));
+ }
cell.appendChild(this.createHeaderLabel_(i));
this.headerInner_.appendChild(cell);
@@ -113,11 +116,11 @@ cr.define('cr.ui.table', function() {
* Appends column splitters to the table header.
*/
appendSplitters_: function() {
- var cm = this.table_.columnModel;
- var splitters = [];
- for (var i = 0; i < cm.size; i++) {
+ const cm = this.table_.columnModel;
+ const splitters = [];
+ for (let i = 0; i < cm.size; i++) {
// splitter should use CSS for background image.
- var splitter = new TableSplitter({table: this.table_});
+ const splitter = new TableSplitter({table: this.table_});
splitter.columnIndex = i;
splitter.addEventListener(
'dblclick', this.handleDblClick_.bind(this, i));
@@ -137,12 +140,13 @@ cr.define('cr.ui.table', function() {
* @param {Array<HTMLElement>|NodeList} splitters Array of splitters.
*/
placeSplitters_: function(splitters) {
- var cm = this.table_.columnModel;
- var place = 0;
- for (var i = 0; i < cm.size; i++) {
+ const cm = this.table_.columnModel;
+ let place = 0;
+ for (let i = 0; i < cm.size; i++) {
// Don't account for the widths of hidden columns.
- if (splitters[i].hidden)
+ if (splitters[i].hidden) {
continue;
+ }
place += cm.getWidth(i);
splitters[i].style.marginInlineStart = place + 'px';
}
@@ -153,24 +157,26 @@ cr.define('cr.ui.table', function() {
* @param {number} index Column index.
*/
createHeaderLabel_: function(index) {
- var cm = this.table_.columnModel;
- var dm = this.table_.dataModel;
+ const cm = this.table_.columnModel;
+ const dm = this.table_.dataModel;
- var labelDiv = this.ownerDocument.createElement('div');
+ const labelDiv = this.ownerDocument.createElement('div');
labelDiv.className = 'table-header-label';
- if (cm.isEndAlign(index))
+ if (cm.isEndAlign(index)) {
labelDiv.style.textAlign = 'end';
- var span = this.ownerDocument.createElement('span');
+ }
+ const span = this.ownerDocument.createElement('span');
span.appendChild(cm.renderHeader(index, this.table_));
span.style.padding = '0';
if (dm) {
if (dm.sortStatus.field == cm.getId(index)) {
- if (dm.sortStatus.direction == 'desc')
+ if (dm.sortStatus.direction == 'desc') {
span.className = 'table-header-sort-image-desc';
- else
+ } else {
span.className = 'table-header-sort-image-asc';
+ }
}
}
labelDiv.appendChild(span);
@@ -194,17 +200,18 @@ cr.define('cr.ui.table', function() {
*/
handleTouchStart_: function(e) {
e = /** @type {TouchEvent} */ (e);
- if (e.touches.length != 1)
+ if (e.touches.length != 1) {
return;
- var clientX = e.touches[0].clientX;
+ }
+ const clientX = e.touches[0].clientX;
- var minDistance = TableHeader.TOUCH_DRAG_AREA_WIDTH;
- var candidate;
+ let minDistance = TableHeader.TOUCH_DRAG_AREA_WIDTH;
+ let candidate;
- var splitters = /** @type {NodeList<cr.ui.TableSplitter>} */ (
+ const splitters = /** @type {NodeList<cr.ui.TableSplitter>} */ (
this.querySelectorAll('.table-header-splitter'));
- for (var i = 0; i < splitters.length; i++) {
- var r = splitters[i].getBoundingClientRect();
+ for (let i = 0; i < splitters.length; i++) {
+ const r = splitters[i].getBoundingClientRect();
if (clientX <= r.left && r.left - clientX <= minDistance) {
minDistance = r.left - clientX;
candidate = splitters[i];
@@ -214,8 +221,9 @@ cr.define('cr.ui.table', function() {
candidate = splitters[i];
}
}
- if (candidate)
+ if (candidate) {
candidate.startDrag(clientX, true);
+ }
// Splitter itself shouldn't handle this event.
e.stopPropagation();
},
@@ -236,15 +244,17 @@ cr.define('cr.ui.table', function() {
* @return {boolean}
*/
needsFullRedraw_: function(headerCells) {
- var cm = this.table_.columnModel;
+ const cm = this.table_.columnModel;
// If the number of columns in the model has changed, a full redraw is
// needed.
- if (headerCells.length != cm.size)
+ if (headerCells.length != cm.size) {
return true;
+ }
// If the column visibility has changed, a full redraw is required.
- for (var i = 0; i < cm.size; i++) {
- if (cm.isVisible(i) == headerCells[i].hidden)
+ for (let i = 0; i < cm.size; i++) {
+ if (cm.isVisible(i) == headerCells[i].hidden) {
return true;
+ }
}
return false;
},
diff --git a/chromium/ui/webui/resources/js/cr/ui/table/table_list.js b/chromium/ui/webui/resources/js/cr/ui/table/table_list.js
index 7937e6c6e7c..0c6c28ff1c7 100644
--- a/chromium/ui/webui/resources/js/cr/ui/table/table_list.js
+++ b/chromium/ui/webui/resources/js/cr/ui/table/table_list.js
@@ -7,8 +7,8 @@
*/
cr.define('cr.ui.table', function() {
- /** @const */ var List = cr.ui.List;
- /** @const */ var ListItem = cr.ui.ListItem;
+ /** @const */ const List = cr.ui.List;
+ /** @const */ const ListItem = cr.ui.ListItem;
/**
* Creates a new table list element.
@@ -16,7 +16,7 @@ cr.define('cr.ui.table', function() {
* @constructor
* @extends {cr.ui.List}
*/
- var TableList = cr.ui.define('list');
+ const TableList = cr.ui.define('list');
TableList.prototype = {
__proto__: List.prototype,
@@ -39,8 +39,9 @@ cr.define('cr.ui.table', function() {
this.redraw();
return;
}
- if (this.updateScrollbars_())
- List.prototype.redraw.call(this); // Redraw items only.
+ if (this.updateScrollbars_()) {
+ List.prototype.redraw.call(this);
+ } // Redraw items only.
this.resizeCells_();
},
@@ -48,13 +49,14 @@ cr.define('cr.ui.table', function() {
* Updates width of cells.
*/
resizeCells_: function() {
- var cm = this.table_.columnModel;
- for (var row = this.firstElementChild; row;
+ const cm = this.table_.columnModel;
+ for (let row = this.firstElementChild; row;
row = row.nextElementSibling) {
- if (row.tagName != 'LI')
+ if (row.tagName != 'LI') {
continue;
+ }
- for (var i = 0; i < cm.size; i++) {
+ for (let i = 0; i < cm.size; i++) {
row.children[i].style.width = cm.getWidth(i) + 'px';
}
row.style.width = cm.totalWidth + 'px';
@@ -66,8 +68,9 @@ cr.define('cr.ui.table', function() {
* Redraws the viewport.
*/
redraw: function() {
- if (this.batchCount_ != 0)
+ if (this.batchCount_ != 0) {
return;
+ }
this.updateScrollbars_();
List.prototype.redraw.call(this);
@@ -93,8 +96,8 @@ cr.define('cr.ui.table', function() {
* @return {boolean} True if horizontal scroll bar changed.
*/
updateScrollbars_: function() {
- var cm = this.table_.columnModel;
- var style = this.style;
+ const cm = this.table_.columnModel;
+ const style = this.style;
if (!cm || cm.size == 0) {
if (style.overflow != 'hidden') {
style.overflow = 'hidden';
@@ -104,9 +107,9 @@ cr.define('cr.ui.table', function() {
}
}
- var height = this.offsetHeight;
- var changed = false;
- var offsetWidth = this.offsetWidth;
+ let height = this.offsetHeight;
+ let changed = false;
+ const offsetWidth = this.offsetWidth;
if (cm.totalWidth > offsetWidth) {
if (style.overflowX != 'scroll') {
style.overflowX = 'scroll';
@@ -122,7 +125,7 @@ cr.define('cr.ui.table', function() {
changed = this.showVerticalScrollBar_(false);
} else {
changed = this.showVerticalScrollBar_(true);
- var x = cm.totalWidth <= this.clientWidth ? 'hidden' : 'scroll';
+ const x = cm.totalWidth <= this.clientWidth ? 'hidden' : 'scroll';
if (style.overflowX != x) {
style.overflowX = x;
}
@@ -136,11 +139,13 @@ cr.define('cr.ui.table', function() {
* @return {boolean} True if visibility changed.
*/
showVerticalScrollBar_: function(show) {
- var style = this.style;
- if (show && style.overflowY == 'scroll')
+ const style = this.style;
+ if (show && style.overflowY == 'scroll') {
return false;
- if (!show && style.overflowY == 'hidden')
+ }
+ if (!show && style.overflowY == 'hidden') {
return false;
+ }
style.overflowY = show ? 'scroll' : 'hidden';
return true;
},
@@ -151,8 +156,9 @@ cr.define('cr.ui.table', function() {
* visibleHeight pixels.
*/
areAllItemsVisible_: function(visibleHeight) {
- if (!this.dataModel || this.dataModel.length == 0)
+ if (!this.dataModel || this.dataModel.length == 0) {
return true;
+ }
return this.getItemTop(this.dataModel.length) <= visibleHeight;
},
@@ -170,16 +176,18 @@ cr.define('cr.ui.table', function() {
* @return {boolean}
*/
needsFullRedraw_: function() {
- var cm = this.table_.columnModel;
- var row = this.firstElementChild;
+ const cm = this.table_.columnModel;
+ const row = this.firstElementChild;
// If the number of columns in the model has changed, a full redraw is
// needed.
- if (row.children.length != cm.size)
+ if (row.children.length != cm.size) {
return true;
+ }
// If the column visibility has changed, a full redraw is required.
- for (var i = 0; i < cm.size; ++i) {
- if (cm.isVisible(i) == row.children[i].hidden)
+ for (let i = 0; i < cm.size; ++i) {
+ if (cm.isVisible(i) == row.children[i].hidden) {
return true;
+ }
}
return false;
},
diff --git a/chromium/ui/webui/resources/js/cr/ui/table/table_splitter.js b/chromium/ui/webui/resources/js/cr/ui/table/table_splitter.js
index 442918f7eeb..41050b6214e 100644
--- a/chromium/ui/webui/resources/js/cr/ui/table/table_splitter.js
+++ b/chromium/ui/webui/resources/js/cr/ui/table/table_splitter.js
@@ -11,7 +11,7 @@
*/
cr.define('cr.ui', function() {
- /** @const */ var Splitter = cr.ui.Splitter;
+ /** @const */ const Splitter = cr.ui.Splitter;
/**
* Creates a new table splitter element.
@@ -19,7 +19,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {cr.ui.Splitter}
*/
- var TableSplitter = cr.ui.define('div');
+ const TableSplitter = cr.ui.define('div');
TableSplitter.prototype = {
__proto__: Splitter.prototype,
@@ -43,7 +43,7 @@ cr.define('cr.ui', function() {
* @override
*/
handleSplitterDragStart: function() {
- var cm = this.table_.columnModel;
+ const cm = this.table_.columnModel;
this.ownerDocument.documentElement.classList.add('col-resize');
this.columnWidth_ = cm.getWidth(this.columnIndex);
diff --git a/chromium/ui/webui/resources/js/cr/ui/tabs.js b/chromium/ui/webui/resources/js/cr/ui/tabs.js
index deccce91703..6ce1d58ea42 100644
--- a/chromium/ui/webui/resources/js/cr/ui/tabs.js
+++ b/chromium/ui/webui/resources/js/cr/ui/tabs.js
@@ -32,9 +32,10 @@ cr.define('cr.ui', function() {
* @this {Tab|TabPanel}
*/
function selectedSetHook(newValue, oldValue) {
- var tabBox;
- if (newValue && (tabBox = getTabBox(this)))
+ let tabBox;
+ if (newValue && (tabBox = getTabBox(this))) {
tabBox.selectedIndex = Array.prototype.indexOf.call(p.children, this);
+ }
}
/**
@@ -42,7 +43,7 @@ cr.define('cr.ui', function() {
* @this {HTMLElement}
*/
function decorateChildren() {
- var map = {
+ const map = {
TABBOX: TabBox,
TABS: Tabs,
TAB: Tab,
@@ -51,9 +52,9 @@ cr.define('cr.ui', function() {
};
Object.keys(map).forEach(function(tagName) {
- var children = this.getElementsByTagName(tagName);
- var constr = map[tagName];
- for (var i = 0; child = children[i]; i++) {
+ const children = this.getElementsByTagName(tagName);
+ const constr = map[tagName];
+ for (let i = 0; child = children[i]; i++) {
cr.ui.decorate(child, constr);
}
}.bind(this));
@@ -65,17 +66,19 @@ cr.define('cr.ui', function() {
* @this {TabBox}
*/
function selectedIndexSetHook(selectedIndex) {
- var child, tabChild, element;
+ let child, tabChild, element;
element = this.querySelector('tabs');
if (element) {
- for (var i = 0; child = element.children[i]; i++) {
+ let i;
+ for (i = 0; child = element.children[i]; i++) {
child.selected = i == selectedIndex;
}
}
element = this.querySelector('tabpanels');
if (element) {
- for (var i = 0; child = element.children[i]; i++) {
+ let i;
+ for (i = 0; child = element.children[i]; i++) {
child.selected = i == selectedIndex;
}
}
@@ -87,7 +90,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var TabBox = cr.ui.define('tabbox');
+ const TabBox = cr.ui.define('tabbox');
TabBox.prototype = {
__proto__: HTMLElement.prototype,
@@ -103,9 +106,9 @@ cr.define('cr.ui', function() {
* @private
*/
handleSelectedChange_: function(e) {
- var target = e.target;
+ const target = e.target;
if (e.newValue && isTabElement(target) && getTabBox(target) == this) {
- var index =
+ const index =
Array.prototype.indexOf.call(target.parentElement.children, target);
this.selectedIndex = index;
}
@@ -127,7 +130,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var Tabs = cr.ui.define('tabs');
+ const Tabs = cr.ui.define('tabs');
Tabs.prototype = {
__proto__: HTMLElement.prototype,
decorate: function() {
@@ -149,7 +152,7 @@ cr.define('cr.ui', function() {
* @private
*/
handleKeyDown_: function(e) {
- var delta = 0;
+ let delta = 0;
switch (e.key) {
case 'ArrowLeft':
case 'ArrowUp':
@@ -161,16 +164,18 @@ cr.define('cr.ui', function() {
break;
}
- if (!delta)
+ if (!delta) {
return;
+ }
- var cs = this.ownerDocument.defaultView.getComputedStyle(this);
- if (cs.direction == 'rtl')
+ const cs = this.ownerDocument.defaultView.getComputedStyle(this);
+ if (cs.direction == 'rtl') {
delta *= -1;
+ }
- var count = this.children.length;
- var tabbox = getTabBox(this);
- var index = tabbox.selectedIndex;
+ const count = this.children.length;
+ const tabbox = getTabBox(this);
+ const index = tabbox.selectedIndex;
tabbox.selectedIndex = (index + delta + count) % count;
// Show focus outline since we used the keyboard.
@@ -184,11 +189,11 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var Tab = cr.ui.define('tab');
+ const Tab = cr.ui.define('tab');
Tab.prototype = {
__proto__: HTMLElement.prototype,
decorate: function() {
- var self = this;
+ const self = this;
this.addEventListener(cr.isMac ? 'click' : 'mousedown', function() {
self.selected = true;
});
@@ -207,7 +212,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var TabPanels = cr.ui.define('tabpanels');
+ const TabPanels = cr.ui.define('tabpanels');
TabPanels.prototype = {
__proto__: HTMLElement.prototype,
decorate: decorateChildren
@@ -219,7 +224,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var TabPanel = cr.ui.define('tabpanel');
+ const TabPanel = cr.ui.define('tabpanel');
TabPanel.prototype = {
__proto__: HTMLElement.prototype,
decorate: function() {}
diff --git a/chromium/ui/webui/resources/js/cr/ui/touch_handler.js b/chromium/ui/webui/resources/js/cr/ui/touch_handler.js
index b30251d0c6c..fa41193dd26 100644
--- a/chromium/ui/webui/resources/js/cr/ui/touch_handler.js
+++ b/chromium/ui/webui/resources/js/cr/ui/touch_handler.js
@@ -140,7 +140,7 @@ cr.define('cr.ui', function() {
*/
TouchHandler.Event = function(
type, bubbles, clientX, clientY, touchedElement) {
- var event = document.createEvent('Event');
+ const event = document.createEvent('Event');
event.initEvent(type, bubbles, true);
event.__proto__ = TouchHandler.Event.prototype;
@@ -198,7 +198,6 @@ cr.define('cr.ui', function() {
*/
TouchHandler.MAX_TRACKING_FOR_TAP_ = 8;
-
/**
* The maximum number of ms to track a touch event. After an event is older
* than this value, it will be ignored in velocity calculations.
@@ -207,7 +206,6 @@ cr.define('cr.ui', function() {
*/
TouchHandler.MAX_TRACKING_TIME_ = 250;
-
/**
* The maximum number of touches to track.
* @type {number}
@@ -215,7 +213,6 @@ cr.define('cr.ui', function() {
*/
TouchHandler.MAX_TRACKING_TOUCHES_ = 5;
-
/**
* The maximum velocity to return, in pixels per millisecond, that is used
* to guard against errors in calculating end velocity of a drag. This is a
@@ -225,7 +222,6 @@ cr.define('cr.ui', function() {
*/
TouchHandler.MAXIMUM_VELOCITY_ = 5;
-
/**
* The velocity to return, in pixel per millisecond, when the time stamps on
* the events are erroneous. The browser can return bad time stamps if the
@@ -350,7 +346,7 @@ cr.define('cr.ui', function() {
* events for mouse input (in addition to touch input).
*/
enable: function(opt_capture, opt_mouse) {
- var capture = !!opt_capture;
+ const capture = !!opt_capture;
// Just listen to start events for now. When a touch is occuring we'll
// want to be subscribed to move and end events on the document, but we
@@ -391,7 +387,7 @@ cr.define('cr.ui', function() {
// client to worry about this if it matters to them (typically a short
// mouseDown/mouseUp without a click is no big problem and it's not
// obvious how we identify such synthesized events in a general way).
- var touch = {
+ const touch = {
// any fixed value will do for the identifier - there will only
// ever be a single active 'touch' when using the mouse.
identifier: 0,
@@ -470,25 +466,28 @@ cr.define('cr.ui', function() {
onStart_: function(e) {
// Only process single touches. If there is already a touch happening, or
// two simultaneous touches then just ignore them.
- if (e.touches.length > 1)
+ if (e.touches.length > 1) {
// Note that we could cancel an active touch here. That would make
// simultaneous touch behave similar to near-simultaneous. However, if
// the user is dragging something, an accidental second touch could be
// quite disruptive if it cancelled their drag. Better to just ignore
// it.
return;
+ }
// It's still possible there could be an active "touch" if the user is
// simultaneously using a mouse and a touch input.
- if (this.activeTouch_ !== undefined)
+ if (this.activeTouch_ !== undefined) {
return;
+ }
- var touch = e.targetTouches[0];
+ const touch = e.targetTouches[0];
this.activeTouch_ = touch.identifier;
// We've just started touching so shouldn't swallow any upcoming click
- if (this.swallowNextClick_)
+ if (this.swallowNextClick_) {
this.swallowNextClick_ = false;
+ }
this.disableTap_ = false;
@@ -548,9 +547,10 @@ cr.define('cr.ui', function() {
assert(this.activeTouch_ !== undefined, 'Expecting an active touch');
// A TouchList isn't actually an array, so we shouldn't use
// Array.prototype.filter/some, etc.
- for (var i = 0; i < touches.length; i++) {
- if (touches[i].identifier == this.activeTouch_)
+ for (let i = 0; i < touches.length; i++) {
+ if (touches[i].identifier == this.activeTouch_) {
return touches[i];
+ }
}
return undefined;
},
@@ -561,32 +561,36 @@ cr.define('cr.ui', function() {
* @private
*/
onMove_: function(e) {
- if (!this.tracking_)
+ if (!this.tracking_) {
return;
+ }
// Our active touch should always be in the list of touches still active
assert(this.findActiveTouch_(e.touches), 'Missing touchEnd');
- var that = this;
- var touch = this.findActiveTouch_(e.changedTouches);
- if (!touch)
+ const that = this;
+ const touch = this.findActiveTouch_(e.changedTouches);
+ if (!touch) {
return;
+ }
- var clientX = touch.clientX;
- var clientY = touch.clientY;
+ const clientX = touch.clientX;
+ const clientY = touch.clientY;
- var moveX = this.lastTouchX_ - clientX;
- var moveY = this.lastTouchY_ - clientY;
+ const moveX = this.lastTouchX_ - clientX;
+ const moveY = this.lastTouchY_ - clientY;
this.totalMoveX_ += Math.abs(moveX);
this.totalMoveY_ += Math.abs(moveY);
this.lastTouchX_ = clientX;
this.lastTouchY_ = clientY;
- var couldBeTap = this.totalMoveY_ <= TouchHandler.MAX_TRACKING_FOR_TAP_ ||
+ const couldBeTap =
+ this.totalMoveY_ <= TouchHandler.MAX_TRACKING_FOR_TAP_ ||
this.totalMoveX_ <= TouchHandler.MAX_TRACKING_FOR_TAP_;
- if (!couldBeTap)
+ if (!couldBeTap) {
this.disableTap_ = true;
+ }
if (this.draggingEnabled_ && !this.dragging_ && !couldBeTap) {
// If we're waiting for a long press, stop
@@ -672,11 +676,11 @@ cr.define('cr.ui', function() {
* @private
*/
onEnd_: function(e) {
- var that = this;
+ const that = this;
assert(this.activeTouch_ !== undefined, 'Expect to already be touching');
// If the touch we're tracking isn't changing here, ignore this touch end.
- var touch = this.findActiveTouch_(e.changedTouches);
+ const touch = this.findActiveTouch_(e.changedTouches);
if (!touch) {
// In most cases, our active touch will be in the 'touches' collection,
// but we can't assert that because occasionally two touchend events can
@@ -694,8 +698,8 @@ cr.define('cr.ui', function() {
this.stopTouching_();
if (this.tracking_) {
- var clientX = touch.clientX;
- var clientY = touch.clientY;
+ const clientX = touch.clientX;
+ const clientY = touch.clientY;
if (this.dragging_) {
this.endTime_ = e.timeStamp;
@@ -722,8 +726,9 @@ cr.define('cr.ui', function() {
// drag-and-drop events are nested inside of the mouse events that trigger
// them).
this.dispatchEvent_(TouchHandler.EventType.TOUCH_END, touch);
- if (!this.disableTap_)
+ if (!this.disableTap_) {
this.dispatchEvent_(TouchHandler.EventType.TAP, touch);
+ }
},
/**
@@ -737,11 +742,11 @@ cr.define('cr.ui', function() {
*/
getEndVelocity: function() {
// Note that we could move velocity to just be an end-event parameter.
- var velocityX = this.recentTouchesX_.length ?
+ let velocityX = this.recentTouchesX_.length ?
(this.endTouchX_ - this.recentTouchesX_[0]) /
(this.endTime_ - this.recentTouchesX_[1]) :
0;
- var velocityY = this.recentTouchesY_.length ?
+ let velocityY = this.recentTouchesY_.length ?
(this.endTouchY_ - this.recentTouchesY_[0]) /
(this.endTime_ - this.recentTouchesY_[1]) :
0;
@@ -761,7 +766,7 @@ cr.define('cr.ui', function() {
* @private
*/
correctVelocity_: function(velocity) {
- var absVelocity = Math.abs(velocity);
+ let absVelocity = Math.abs(velocity);
// We add to recent touches for each touchstart and touchmove. If we have
// fewer than 3 touches (6 entries), we assume that the thread was blocked
@@ -825,7 +830,7 @@ cr.define('cr.ui', function() {
// touch is our primary scenario (which we want to emulate with mouse),
// we'll treat both cases the same and not depend on the target.
/** @type {Element} */
- var touchedElement;
+ let touchedElement;
if (eventType == TouchHandler.EventType.TOUCH_START) {
touchedElement = assertInstanceof(touch.target, Element);
} else {
@@ -848,23 +853,24 @@ cr.define('cr.ui', function() {
* @private
*/
dispatchEventXY_: function(eventType, touchedElement, clientX, clientY) {
- var isDrag =
+ const isDrag =
(eventType == TouchHandler.EventType.DRAG_START ||
eventType == TouchHandler.EventType.DRAG_MOVE ||
eventType == TouchHandler.EventType.DRAG_END);
// Drag events don't bubble - we're really just dragging the element,
// not affecting its parent at all.
- var bubbles = !isDrag;
+ const bubbles = !isDrag;
- var event = new TouchHandler.Event(
+ const event = new TouchHandler.Event(
eventType, bubbles, clientX, clientY, touchedElement);
// Set enableDrag when it can be overridden
- if (eventType == TouchHandler.EventType.TOUCH_START)
+ if (eventType == TouchHandler.EventType.TOUCH_START) {
event.enableDrag = false;
- else if (eventType == TouchHandler.EventType.DRAG_START)
+ } else if (eventType == TouchHandler.EventType.DRAG_START) {
event.enableDrag = true;
+ }
if (isDrag) {
event.dragDeltaX = clientX - this.startTouchX_;
diff --git a/chromium/ui/webui/resources/js/cr/ui/tree.js b/chromium/ui/webui/resources/js/cr/ui/tree.js
index 3dc541dfbb6..239cde0df82 100644
--- a/chromium/ui/webui/resources/js/cr/ui/tree.js
+++ b/chromium/ui/webui/resources/js/cr/ui/tree.js
@@ -11,7 +11,7 @@ cr.define('cr.ui', function() {
* @type {number}
* @const
*/
- var INDENT = 20;
+ const INDENT = 20;
/**
* Returns the computed style for an element.
@@ -40,7 +40,7 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var Tree = cr.ui.define('tree');
+ const Tree = cr.ui.define('tree');
Tree.prototype = {
__proto__: HTMLElement.prototype,
@@ -50,16 +50,18 @@ cr.define('cr.ui', function() {
*/
decorate: function() {
// Make list focusable
- if (!this.hasAttribute('tabindex'))
+ if (!this.hasAttribute('tabindex')) {
this.tabIndex = 0;
+ }
this.addEventListener('click', this.handleClick);
this.addEventListener('mousedown', this.handleMouseDown);
this.addEventListener('dblclick', this.handleDblClick);
this.addEventListener('keydown', this.handleKeyDown);
- if (!this.hasAttribute('role'))
+ if (!this.hasAttribute('role')) {
this.setAttribute('role', 'group');
+ }
},
/**
@@ -113,14 +115,16 @@ cr.define('cr.ui', function() {
* @param {Event} e The click event object.
*/
handleClick: function(e) {
- var treeItem = findTreeItem(/** @type {!Node} */ (e.target));
- if (treeItem)
+ const treeItem = findTreeItem(/** @type {!Node} */ (e.target));
+ if (treeItem) {
treeItem.handleClick(e);
+ }
},
handleMouseDown: function(e) {
- if (e.button == 2) // right
+ if (e.button == 2) { // right
this.handleClick(e);
+ }
},
/**
@@ -128,9 +132,10 @@ cr.define('cr.ui', function() {
* @param {Event} e The dblclick event object.
*/
handleDblClick: function(e) {
- var treeItem = findTreeItem(/** @type {!Node} */ (e.target));
- if (treeItem)
+ const treeItem = findTreeItem(/** @type {!Node} */ (e.target));
+ if (treeItem) {
treeItem.expanded = !treeItem.expanded;
+ }
},
/**
@@ -139,15 +144,17 @@ cr.define('cr.ui', function() {
* @param {Event} e The click event object.
*/
handleKeyDown: function(e) {
- var itemToSelect;
- if (e.ctrlKey)
+ let itemToSelect;
+ if (e.ctrlKey) {
return;
+ }
- var item = this.selectedItem;
- if (!item)
+ const item = this.selectedItem;
+ if (!item) {
return;
+ }
- var rtl = getComputedStyle(item).direction == 'rtl';
+ const rtl = getComputedStyle(item).direction == 'rtl';
switch (e.key) {
case 'ArrowUp':
@@ -160,19 +167,22 @@ cr.define('cr.ui', function() {
case 'ArrowLeft':
case 'ArrowRight':
// Don't let back/forward keyboard shortcuts be used.
- if (!cr.isMac && e.altKey || cr.isMac && e.metaKey)
+ if (!cr.isMac && e.altKey || cr.isMac && e.metaKey) {
break;
+ }
if (e.key == 'ArrowLeft' && !rtl || e.key == 'ArrowRight' && rtl) {
- if (item.expanded)
+ if (item.expanded) {
item.expanded = false;
- else
+ } else {
itemToSelect = findTreeItem(item.parentNode);
+ }
} else {
- if (!item.expanded)
+ if (!item.expanded) {
item.expanded = true;
- else
+ } else {
itemToSelect = item.items[0];
+ }
}
break;
case 'Home':
@@ -197,19 +207,21 @@ cr.define('cr.ui', function() {
return this.selectedItem_ || null;
},
set selectedItem(item) {
- var oldSelectedItem = this.selectedItem_;
+ const oldSelectedItem = this.selectedItem_;
if (oldSelectedItem != item) {
// Set the selectedItem_ before deselecting the old item since we only
// want one change when moving between items.
this.selectedItem_ = item;
- if (oldSelectedItem)
+ if (oldSelectedItem) {
oldSelectedItem.selected = false;
+ }
if (item) {
item.selected = true;
- if (item.id)
+ if (item.id) {
this.setAttribute('aria-activedescendant', item.id);
+ }
} else {
this.removeAttribute('aria-activedescendant');
}
@@ -223,8 +235,9 @@ cr.define('cr.ui', function() {
getRectForContextMenu: function() {
// TODO(arv): Add trait support so we can share more code between trees
// and lists.
- if (this.selectedItem)
+ if (this.selectedItem) {
return this.selectedItem.rowElement.getBoundingClientRect();
+ }
return this.getBoundingClientRect();
}
};
@@ -245,14 +258,14 @@ cr.define('cr.ui', function() {
*
* @type {number}
*/
- var treeItemAutoGeneratedIdCounter = 0;
+ let treeItemAutoGeneratedIdCounter = 0;
/**
* This is used as a blueprint for new tree item elements.
* @type {!HTMLElement}
*/
- var treeItemProto = (function() {
- var treeItem = cr.doc.createElement('div');
+ const treeItemProto = (function() {
+ const treeItem = cr.doc.createElement('div');
treeItem.className = 'tree-item';
treeItem.innerHTML = '<div class="tree-row">' +
'<span class="expand-icon"></span>' +
@@ -269,8 +282,8 @@ cr.define('cr.ui', function() {
* @constructor
* @extends {HTMLElement}
*/
- var TreeItem = cr.ui.define(function() {
- var treeItem = treeItemProto.cloneNode(true);
+ const TreeItem = cr.ui.define(function() {
+ const treeItem = treeItemProto.cloneNode(true);
treeItem.id = 'tree-item-autogen-id-' + treeItemAutoGeneratedIdCounter++;
return treeItem;
});
@@ -282,7 +295,7 @@ cr.define('cr.ui', function() {
* Initializes the element.
*/
decorate: function() {
- var labelId =
+ const labelId =
'tree-item-label-autogen-id-' + treeItemAutoGeneratedIdCounter;
this.labelElement.id = labelId;
this.setAttribute('aria-labelledby', labelId);
@@ -314,8 +327,8 @@ cr.define('cr.ui', function() {
this.rowElement.style.paddingInlineStart =
Math.max(0, depth - 1) * INDENT + 'px';
this.depth_ = depth;
- var items = this.items;
- for (var i = 0, item; item = items[i]; i++) {
+ const items = this.items;
+ for (let i = 0, item; item = items[i]; i++) {
item.setDepth_(depth + 1);
}
}
@@ -336,8 +349,9 @@ cr.define('cr.ui', function() {
*/
addAt: function(child, index) {
this.lastElementChild.insertBefore(child, this.items[index]);
- if (this.items.length == 1)
+ if (this.items.length == 1) {
this.hasChildren = true;
+ }
child.setDepth_(this.depth + 1);
},
@@ -348,14 +362,16 @@ cr.define('cr.ui', function() {
*/
remove: function(child) {
// If we removed the selected item we should become selected.
- var tree = this.tree;
- var selectedItem = tree.selectedItem;
- if (selectedItem && child.contains(selectedItem))
+ const tree = this.tree;
+ const selectedItem = tree.selectedItem;
+ if (selectedItem && child.contains(selectedItem)) {
this.selected = true;
+ }
this.lastElementChild.removeChild(/** @type {!cr.ui.TreeItem} */ (child));
- if (this.items.length == 0)
+ if (this.items.length == 0) {
this.hasChildren = false;
+ }
},
/**
@@ -363,7 +379,7 @@ cr.define('cr.ui', function() {
* @type {!cr.ui.Tree|cr.ui.TreeItem}
*/
get parentItem() {
- var p = this.parentNode;
+ let p = this.parentNode;
while (p && !(p instanceof TreeItem) && !(p instanceof Tree)) {
p = p.parentNode;
}
@@ -375,7 +391,7 @@ cr.define('cr.ui', function() {
* @type {cr.ui.Tree}
*/
get tree() {
- var t = this.parentItem;
+ let t = this.parentItem;
while (t && !(t instanceof Tree)) {
t = t.parentItem;
}
@@ -390,10 +406,11 @@ cr.define('cr.ui', function() {
return this.hasAttribute('expanded');
},
set expanded(b) {
- if (this.expanded == b)
+ if (this.expanded == b) {
return;
+ }
- var treeChildren = this.lastElementChild;
+ const treeChildren = this.lastElementChild;
if (b) {
if (this.mayHaveChildren_) {
@@ -404,17 +421,19 @@ cr.define('cr.ui', function() {
this.scrollIntoViewIfNeeded(false);
}
} else {
- var tree = this.tree;
+ const tree = this.tree;
if (tree && !this.selected) {
- var oldSelected = tree.selectedItem;
- if (oldSelected && this.contains(oldSelected))
+ const oldSelected = tree.selectedItem;
+ if (oldSelected && this.contains(oldSelected)) {
this.selected = true;
+ }
}
this.removeAttribute('expanded');
- if (this.mayHaveChildren_)
+ if (this.mayHaveChildren_) {
this.setAttribute('aria-expanded', 'false');
- else
+ } else {
this.removeAttribute('aria-expanded');
+ }
treeChildren.removeAttribute('expanded');
cr.dispatchSimpleEvent(this, 'collapse', true);
}
@@ -424,7 +443,7 @@ cr.define('cr.ui', function() {
* Expands all parent items.
*/
reveal: function() {
- var pi = this.parentItem;
+ let pi = this.parentItem;
while (pi && !(pi instanceof Tree)) {
pi.expanded = true;
pi = pi.parentItem;
@@ -477,22 +496,25 @@ cr.define('cr.ui', function() {
return this.hasAttribute('selected');
},
set selected(b) {
- if (this.selected == b)
+ if (this.selected == b) {
return;
- var rowItem = this.firstElementChild;
- var tree = this.tree;
+ }
+ const rowItem = this.firstElementChild;
+ const tree = this.tree;
if (b) {
this.setAttribute('selected', '');
rowItem.setAttribute('selected', '');
this.reveal();
this.labelElement.scrollIntoViewIfNeeded(false);
- if (tree)
+ if (tree) {
tree.selectedItem = this;
+ }
} else {
this.removeAttribute('selected');
rowItem.removeAttribute('selected');
- if (tree && tree.selectedItem == this)
+ if (tree && tree.selectedItem == this) {
tree.selectedItem = null;
+ }
}
},
@@ -504,7 +526,7 @@ cr.define('cr.ui', function() {
return this.hasAttribute('may-have-children');
},
set mayHaveChildren_(b) {
- var rowItem = this.firstElementChild;
+ const rowItem = this.firstElementChild;
if (b) {
this.setAttribute('may-have-children', '');
rowItem.setAttribute('may-have-children', '');
@@ -527,7 +549,7 @@ cr.define('cr.ui', function() {
* @type {boolean}
*/
set hasChildren(b) {
- var rowItem = this.firstElementChild;
+ const rowItem = this.firstElementChild;
this.setAttribute('has-children', b);
rowItem.setAttribute('has-children', b);
if (b) {
@@ -542,10 +564,11 @@ cr.define('cr.ui', function() {
* @param {Event} e The click event.
*/
handleClick: function(e) {
- if (e.target.className == 'expand-icon')
+ if (e.target.className == 'expand-icon') {
this.expanded = !this.expanded;
- else
+ } else {
this.selected = true;
+ }
},
/**
@@ -554,14 +577,15 @@ cr.define('cr.ui', function() {
* @type {boolean}
*/
set editing(editing) {
- var oldEditing = this.editing;
- if (editing == oldEditing)
+ const oldEditing = this.editing;
+ if (editing == oldEditing) {
return;
+ }
- var self = this;
- var labelEl = this.labelElement;
- var text = this.label;
- var input;
+ const self = this;
+ const labelEl = this.labelElement;
+ const text = this.label;
+ let input;
// Handles enter and escape which trigger reset and commit respectively.
function handleKeydown(e) {
@@ -592,10 +616,11 @@ cr.define('cr.ui', function() {
// the input loses focus we set editing to false again.
input = this.ownerDocument.createElement('input');
input.value = text;
- if (labelEl.firstChild)
+ if (labelEl.firstChild) {
labelEl.replaceChild(input, labelEl.firstChild);
- else
+ } else {
labelEl.appendChild(input);
+ }
input.addEventListener('keydown', handleKeydown);
input.addEventListener('blur', (function() {
@@ -604,14 +629,15 @@ cr.define('cr.ui', function() {
// Make sure that double clicks do not expand and collapse the tree
// item.
- var eventsToStop = ['mousedown', 'mouseup', 'contextmenu', 'dblclick'];
+ const eventsToStop =
+ ['mousedown', 'mouseup', 'contextmenu', 'dblclick'];
eventsToStop.forEach(function(type) {
input.addEventListener(type, stopPropagation);
});
// Wait for the input element to recieve focus before sizing it.
- var rowElement = this.rowElement;
- var onFocus = function() {
+ const rowElement = this.rowElement;
+ const onFocus = function() {
input.removeEventListener('focus', onFocus);
// 20 = the padding and border of the tree-row
cr.ui.limitInputWidth(input, rowElement, 100);
@@ -625,7 +651,7 @@ cr.define('cr.ui', function() {
this.removeAttribute('editing');
this.draggable = true;
input = labelEl.firstChild;
- var value = input.value;
+ const value = input.value;
if (/^\s*$/.test(value)) {
labelEl.textContent = this.oldLabel_;
} else {
@@ -650,7 +676,7 @@ cr.define('cr.ui', function() {
*/
function getNext(item) {
if (item.expanded) {
- var firstChild = item.items[0];
+ const firstChild = item.items[0];
if (firstChild) {
return firstChild;
}
@@ -665,12 +691,14 @@ cr.define('cr.ui', function() {
* @return {cr.ui.TreeItem} The found item or null.
*/
function getNextHelper(item) {
- if (!item)
+ if (!item) {
return null;
+ }
- var nextSibling = item.nextElementSibling;
- if (nextSibling)
+ const nextSibling = item.nextElementSibling;
+ if (nextSibling) {
return assertInstanceof(nextSibling, cr.ui.TreeItem);
+ }
return getNextHelper(item.parentItem);
}
@@ -680,9 +708,10 @@ cr.define('cr.ui', function() {
* @return {cr.ui.TreeItem} The found item or null.
*/
function getPrevious(item) {
- var previousSibling = item.previousElementSibling;
- if (previousSibling)
+ const previousSibling = item.previousElementSibling;
+ if (previousSibling) {
return getLastHelper(assertInstanceof(previousSibling, cr.ui.TreeItem));
+ }
return item.parentItem;
}
@@ -692,10 +721,11 @@ cr.define('cr.ui', function() {
* @return {cr.ui.TreeItem} The found item or null.
*/
function getLastHelper(item) {
- if (!item)
+ if (!item) {
return null;
+ }
if (item.expanded && item.hasChildren) {
- var lastChild = item.items[item.items.length - 1];
+ const lastChild = item.items[item.items.length - 1];
return getLastHelper(lastChild);
}
return item;
diff --git a/chromium/ui/webui/resources/js/dark_mode.js b/chromium/ui/webui/resources/js/dark_mode.js
new file mode 100644
index 00000000000..0ba4cb62fb2
--- /dev/null
+++ b/chromium/ui/webui/resources/js/dark_mode.js
@@ -0,0 +1,10 @@
+// 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.
+
+cr.addWebUIListener('dark-mode-changed', darkMode => {
+ loadTimeData.overrideValues({'darkMode': darkMode});
+ document.documentElement.toggleAttribute('dark', darkMode);
+});
+
+chrome.send('observeDarkMode');
diff --git a/chromium/ui/webui/resources/js/event_tracker.js b/chromium/ui/webui/resources/js/event_tracker.js
index 126c6f5b247..828295bc17c 100644
--- a/chromium/ui/webui/resources/js/event_tracker.js
+++ b/chromium/ui/webui/resources/js/event_tracker.js
@@ -20,6 +20,7 @@
* listener: (EventListener|Function),
* capture: boolean}}
*/
+// eslint-disable-next-line no-var
var EventTrackerEntry;
/**
@@ -46,8 +47,8 @@ EventTracker.prototype = {
* @param {boolean=} opt_capture Whether to invoke during the capture phase.
*/
add: function(target, eventType, listener, opt_capture) {
- var capture = !!opt_capture;
- var h = {
+ const capture = !!opt_capture;
+ const h = {
target: target,
eventType: eventType,
listener: listener,
diff --git a/chromium/ui/webui/resources/js/find_shortcut_behavior.js b/chromium/ui/webui/resources/js/find_shortcut_behavior.js
new file mode 100644
index 00000000000..fe88a2bf468
--- /dev/null
+++ b/chromium/ui/webui/resources/js/find_shortcut_behavior.js
@@ -0,0 +1,114 @@
+// 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 Listens for a find keyboard shortcut (i.e. Ctrl/Cmd+f)
+ * and keeps track of an stack of potential listeners. Only the listener at the
+ * top of the stack will be notified that a find shortcut has been invoked.
+ */
+
+const FindShortcutManager = (() => {
+ /**
+ * Stack of listeners. Only the top listener will handle the shortcut.
+ * @type {!Array}
+ */
+ const listeners = [];
+
+ /**
+ * Tracks if any modal context is open in settings. This assumes only one
+ * modal can be open at a time. The modals that are being tracked include
+ * cr-dialog and cr-drawer.
+ * @type {boolean}
+ */
+ let modalContextOpen = false;
+
+ const shortcut =
+ new cr.ui.KeyboardShortcutList(cr.isMac ? 'meta|f' : 'ctrl|f');
+
+ window.addEventListener('keydown', e => {
+ if (e.defaultPrevented || listeners.length == 0 ||
+ !shortcut.matchesEvent(e)) {
+ return;
+ }
+
+ const focusIndex =
+ listeners.findIndex(listener => listener.searchInputHasFocus());
+ // If no listener has focus or the first (outer-most) listener has focus,
+ // try the last (inner-most) listener.
+ // If a listener has a search input with focus, the next listener that
+ // should be called is the right before it in |listeners| such that the
+ // goes from inner-most to outer-most.
+ const index = focusIndex <= 0 ? listeners.length - 1 : focusIndex - 1;
+ if (listeners[index].handleFindShortcut(modalContextOpen)) {
+ e.preventDefault();
+ }
+ });
+
+ window.addEventListener('cr-dialog-open', () => {
+ modalContextOpen = true;
+ });
+
+ window.addEventListener('cr-drawer-opened', () => {
+ modalContextOpen = true;
+ });
+
+ window.addEventListener('close', e => {
+ if (['CR-DIALOG', 'CR-DRAWER'].includes(e.composedPath()[0].nodeName)) {
+ modalContextOpen = false;
+ }
+ });
+
+ return Object.freeze({listeners: listeners});
+})();
+
+/**
+ * Used to determine how to handle find shortcut invocations.
+ * @polymerBehavior
+ */
+const FindShortcutBehavior = {
+ /**
+ * @type {boolean}
+ * @protected
+ */
+ findShortcutListenOnAttach: true,
+
+ attached: function() {
+ if (this.findShortcutListenOnAttach) {
+ this.becomeActiveFindShortcutListener();
+ }
+ },
+
+ detached: function() {
+ if (this.findShortcutListenOnAttach) {
+ this.removeSelfAsFindShortcutListener();
+ }
+ },
+
+ becomeActiveFindShortcutListener: function() {
+ const listeners = FindShortcutManager.listeners;
+ assert(!listeners.includes(this), 'Already listening for find shortcuts.');
+ listeners.push(this);
+ },
+
+ /**
+ * If handled, return true.
+ * @param {boolean} modalContextOpen
+ * @return {boolean}
+ */
+ handleFindShortcut: function(modalContextOpen) {
+ assertNotReached();
+ },
+
+ removeSelfAsFindShortcutListener: function() {
+ const listeners = FindShortcutManager.listeners;
+ const index = listeners.indexOf(this);
+ assert(listeners.includes(this), 'Find shortcut listener not found.');
+ listeners.splice(index, 1);
+ },
+
+ /** @return {boolean} */
+ searchInputHasFocus: function() {
+ assertNotReached();
+ },
+};
diff --git a/chromium/ui/webui/resources/js/i18n_behavior.js b/chromium/ui/webui/resources/js/i18n_behavior.js
index 2f8a129be33..4f4540fea92 100644
--- a/chromium/ui/webui/resources/js/i18n_behavior.js
+++ b/chromium/ui/webui/resources/js/i18n_behavior.js
@@ -9,7 +9,7 @@
*/
/** @polymerBehavior */
-var I18nBehavior = {
+const I18nBehavior = {
properties: {
/**
* The language the UI is presented in. Used to signal dynamic language
@@ -46,7 +46,7 @@ var I18nBehavior = {
* @return {string} A translated, sanitized, substituted string.
*/
i18n: function(id, var_args) {
- var rawString = this.i18nRaw_.apply(this, arguments);
+ const rawString = this.i18nRaw_.apply(this, arguments);
return parseHtmlSubset('<b>' + rawString + '</b>').firstChild.textContent;
},
@@ -61,8 +61,8 @@ var I18nBehavior = {
*/
i18nAdvanced: function(id, opts) {
opts = opts || {};
- var args = [id].concat(opts.substitutions || []);
- var rawString = this.i18nRaw_.apply(this, args);
+ const args = [id].concat(opts.substitutions || []);
+ const rawString = this.i18nRaw_.apply(this, args);
return loadTimeData.sanitizeInnerHtml(rawString, opts);
},
@@ -91,10 +91,10 @@ var I18nBehavior = {
* @return {string} A translated, sanitized, substituted string.
*/
i18nRecursive: function(locale, id, var_args) {
- var args = Array.prototype.slice.call(arguments, 2);
+ let args = Array.prototype.slice.call(arguments, 2);
if (args.length > 0) {
// Try to replace IDs with localized values.
- var self = this;
+ const self = this;
args = args.map(function(str) {
return self.i18nExists(str) ? loadTimeData.getString(str) : str;
});
diff --git a/chromium/ui/webui/resources/js/i18n_template_no_process.js b/chromium/ui/webui/resources/js/i18n_template_no_process.js
index 94af5c8465a..523557b1e31 100644
--- a/chromium/ui/webui/resources/js/i18n_template_no_process.js
+++ b/chromium/ui/webui/resources/js/i18n_template_no_process.js
@@ -3,7 +3,7 @@
// found in the LICENSE file.
/** @typedef {Document|DocumentFragment|Element} */
-var ProcessingRoot;
+let ProcessingRoot;
/**
* @fileoverview This is a simple template engine inspired by JsTemplates
@@ -28,6 +28,7 @@ var ProcessingRoot;
* load_time_data.js. It should replace i18n_template.js eventually.
*/
+// eslint-disable-next-line no-var
var i18nTemplate = (function() {
/**
* This provides the handlers for the templating engine. The key is used as
@@ -35,7 +36,7 @@ var i18nTemplate = (function() {
* single node that has this attribute.
* @type {!Object}
*/
- var handlers = {
+ const handlers = {
/**
* This handler sets the textContent of the element.
* @param {!HTMLElement} element The node to modify.
@@ -58,9 +59,9 @@ var i18nTemplate = (function() {
* @param {!Set<ProcessingRoot>} visited
*/
'i18n-options': function(select, key, data, visited) {
- var options = data.getValue(key);
+ const options = data.getValue(key);
options.forEach(function(optionData) {
- var option = typeof optionData == 'string' ?
+ const option = typeof optionData == 'string' ?
new Option(optionData) :
new Option(optionData[1], optionData[0]);
select.appendChild(option);
@@ -80,25 +81,27 @@ var i18nTemplate = (function() {
* @param {!Set<ProcessingRoot>} visited
*/
'i18n-values': function(element, attributeAndKeys, data, visited) {
- var parts = attributeAndKeys.replace(/\s/g, '').split(/;/);
+ const parts = attributeAndKeys.replace(/\s/g, '').split(/;/);
parts.forEach(function(part) {
- if (!part)
+ if (!part) {
return;
+ }
- var attributeAndKeyPair = part.match(/^([^:]+):(.+)$/);
- if (!attributeAndKeyPair)
+ const attributeAndKeyPair = part.match(/^([^:]+):(.+)$/);
+ if (!attributeAndKeyPair) {
throw new Error('malformed i18n-values: ' + attributeAndKeys);
+ }
- var propName = attributeAndKeyPair[1];
- var propExpr = attributeAndKeyPair[2];
+ const propName = attributeAndKeyPair[1];
+ const propExpr = attributeAndKeyPair[2];
- var value = data.getValue(propExpr);
+ const value = data.getValue(propExpr);
// Allow a property of the form '.foo.bar' to assign a value into
// element.foo.bar.
if (propName[0] == '.') {
- var path = propName.slice(1).split('.');
- var targetObject = element;
+ const path = propName.slice(1).split('.');
+ let targetObject = element;
while (targetObject && path.length > 1) {
targetObject = targetObject[path.shift()];
}
@@ -107,7 +110,7 @@ var i18nTemplate = (function() {
// In case we set innerHTML (ignoring others) we need to recursively
// check the content.
if (path == 'innerHTML') {
- for (var i = 0; i < element.children.length; ++i) {
+ for (let i = 0; i < element.children.length; ++i) {
processWithoutCycles(element.children[i], data, visited, false);
}
}
@@ -119,20 +122,21 @@ var i18nTemplate = (function() {
}
};
- var prefixes = [''];
+ const prefixes = [''];
// Only look through shadow DOM when it's supported. As of April 2015, iOS
// Chrome doesn't support shadow DOM.
- if (Element.prototype.createShadowRoot)
+ if (Element.prototype.createShadowRoot) {
prefixes.push('* /deep/ ');
+ }
- var attributeNames = Object.keys(handlers);
- var selector = prefixes
- .map(function(prefix) {
- return prefix + '[' +
- attributeNames.join('], ' + prefix + '[') + ']';
- })
- .join(', ');
+ const attributeNames = Object.keys(handlers);
+ const selector = prefixes
+ .map(function(prefix) {
+ return prefix + '[' +
+ attributeNames.join('], ' + prefix + '[') + ']';
+ })
+ .join(', ');
/**
* Processes a DOM tree using a |data| source to populate template values.
@@ -159,9 +163,9 @@ var i18nTemplate = (function() {
// Mark the node as visited before recursing.
visited.add(root);
- var importLinks = root.querySelectorAll('link[rel=import]');
- for (var i = 0; i < importLinks.length; ++i) {
- var importLink = /** @type {!HTMLLinkElement} */ (importLinks[i]);
+ const importLinks = root.querySelectorAll('link[rel=import]');
+ for (let i = 0; i < importLinks.length; ++i) {
+ const importLink = /** @type {!HTMLLinkElement} */ (importLinks[i]);
if (!importLink.import) {
// Happens when a <link rel=import> is inside a <template>.
// TODO(dbeam): should we log an error if we detect that here?
@@ -170,27 +174,29 @@ var i18nTemplate = (function() {
processWithoutCycles(importLink.import, data, visited, mark);
}
- var templates = root.querySelectorAll('template');
- for (var i = 0; i < templates.length; ++i) {
- var template = /** @type {HTMLTemplateElement} */ (templates[i]);
- if (!template.content)
+ const templates = root.querySelectorAll('template');
+ for (let i = 0; i < templates.length; ++i) {
+ const template = /** @type {HTMLTemplateElement} */ (templates[i]);
+ if (!template.content) {
continue;
+ }
processWithoutCycles(template.content, data, visited, mark);
}
- var isElement = root instanceof Element;
- if (isElement && root.webkitMatchesSelector(selector))
+ const isElement = root instanceof Element;
+ if (isElement && root.webkitMatchesSelector(selector)) {
processElement(/** @type {!Element} */ (root), data, visited);
+ }
- var elements = root.querySelectorAll(selector);
- for (var i = 0; i < elements.length; ++i) {
+ const elements = root.querySelectorAll(selector);
+ for (let i = 0; i < elements.length; ++i) {
processElement(elements[i], data, visited);
}
if (mark) {
- var processed = isElement ? [root] : root.children;
+ const processed = isElement ? [root] : root.children;
if (processed) {
- for (var i = 0; i < processed.length; ++i) {
+ for (let i = 0; i < processed.length; ++i) {
processed[i].setAttribute('i18n-processed', '');
}
}
@@ -204,11 +210,12 @@ var i18nTemplate = (function() {
* @param {!Set<ProcessingRoot>} visited
*/
function processElement(element, data, visited) {
- for (var i = 0; i < attributeNames.length; i++) {
- var name = attributeNames[i];
- var attribute = element.getAttribute(name);
- if (attribute != null)
+ for (let i = 0; i < attributeNames.length; i++) {
+ const name = attributeNames[i];
+ const attribute = element.getAttribute(name);
+ if (attribute != null) {
handlers[name](element, attribute, data, visited);
+ }
}
}
diff --git a/chromium/ui/webui/resources/js/icon.js b/chromium/ui/webui/resources/js/icon.js
index ef025e7133d..094eae8245d 100644
--- a/chromium/ui/webui/resources/js/icon.js
+++ b/chromium/ui/webui/resources/js/icon.js
@@ -8,7 +8,7 @@ cr.define('cr.icon', function() {
* webui resources.
*/
function getSupportedScaleFactors() {
- var supportedScaleFactors = [];
+ const supportedScaleFactors = [];
if (!cr.isIOS) {
// This matches the code in ResourceBundle::InitSharedInstance() that
// supports SCALE_FACTOR_100P on all non-iOS platforms.
@@ -31,6 +31,16 @@ cr.define('cr.icon', function() {
}
/**
+ * A URL for the filetype icon for |filePath|. OS and theme dependent.
+ * @param {string} filePath
+ * @return {string}
+ */
+ function getFileIconUrl(filePath) {
+ return 'chrome://fileicon/' + encodeURIComponent(filePath) +
+ '?scale=' + window.devicePixelRatio + 'x';
+ }
+
+ /**
* Generates a CSS -webkit-image-set for a chrome:// url.
* An entry in the image set is added for each of getSupportedScaleFactors().
* The scale-factor-specific url is generated by replacing the first instance
@@ -41,22 +51,24 @@ cr.define('cr.icon', function() {
* @return {string} The CSS -webkit-image-set.
*/
function getImageSet(path) {
- var supportedScaleFactors = getSupportedScaleFactors();
+ const supportedScaleFactors = getSupportedScaleFactors();
- var replaceStartIndex = path.indexOf('scalefactor');
- if (replaceStartIndex < 0)
+ const replaceStartIndex = path.indexOf('scalefactor');
+ if (replaceStartIndex < 0) {
return getUrlForCss(path);
+ }
- var s = '';
- for (var i = 0; i < supportedScaleFactors.length; ++i) {
- var scaleFactor = supportedScaleFactors[i];
- var pathWithScaleFactor = path.substr(0, replaceStartIndex) +
+ let s = '';
+ for (let i = 0; i < supportedScaleFactors.length; ++i) {
+ const scaleFactor = supportedScaleFactors[i];
+ const pathWithScaleFactor = path.substr(0, replaceStartIndex) +
scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length);
s += getUrlForCss(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
- if (i != supportedScaleFactors.length - 1)
+ if (i != supportedScaleFactors.length - 1) {
s += ', ';
+ }
}
return '-webkit-image-set(' + s + ')';
}
@@ -69,8 +81,8 @@ cr.define('cr.icon', function() {
* @return {string} The url, or an image set of URLs.
*/
function getImage(path) {
- var chromeThemePath = 'chrome://theme';
- var isChromeThemeUrl =
+ const chromeThemePath = 'chrome://theme';
+ const isChromeThemeUrl =
(path.slice(0, chromeThemePath.length) == chromeThemePath);
return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') :
getUrlForCss(path);
@@ -80,7 +92,7 @@ cr.define('cr.icon', function() {
* A regular expression for identifying favicon URLs.
* @const {!RegExp}
*/
- var FAVICON_URL_REGEX = /\.ico$/i;
+ const FAVICON_URL_REGEX = /\.ico$/i;
/**
* Creates a CSS -webkit-image-set for a favicon request.
@@ -100,5 +112,6 @@ cr.define('cr.icon', function() {
return {
getImage: getImage,
getFavicon: getFavicon,
+ getFileIconUrl: getFileIconUrl,
};
});
diff --git a/chromium/ui/webui/resources/js/list_property_update_behavior.js b/chromium/ui/webui/resources/js/list_property_update_behavior.js
index 5606878986a..260f57c4b78 100644
--- a/chromium/ui/webui/resources/js/list_property_update_behavior.js
+++ b/chromium/ui/webui/resources/js/list_property_update_behavior.js
@@ -39,7 +39,8 @@ const ListPropertyUpdateBehavior = {
const spliceParams = [index, deleteCount].concat(added);
list.splice.apply(list, spliceParams);
});
- if (splices.length > 0)
+ if (splices.length > 0) {
this.notifySplices(propertyName, splices);
+ }
},
};
diff --git a/chromium/ui/webui/resources/js/load_time_data.js b/chromium/ui/webui/resources/js/load_time_data.js
index b6f8ff091d7..e8586d9c745 100644
--- a/chromium/ui/webui/resources/js/load_time_data.js
+++ b/chromium/ui/webui/resources/js/load_time_data.js
@@ -21,8 +21,9 @@
* tags: (Array<string>|undefined),
* }}
*/
-var SanitizeInnerHtmlOpts;
+let SanitizeInnerHtmlOpts;
+// eslint-disable-next-line no-var
/** @type {!LoadTimeData} */ var loadTimeData;
// Expose this type globally as a temporary work around until
@@ -71,7 +72,7 @@ function LoadTimeData(){}
*/
getValue: function(id) {
expect(this.data_, 'No data. Did you remember to include strings.js?');
- var value = this.data_[id];
+ const value = this.data_[id];
expect(typeof value != 'undefined', 'Could not find value for ' + id);
return value;
},
@@ -82,7 +83,7 @@ function LoadTimeData(){}
* @return {string} The corresponding string value.
*/
getString: function(id) {
- var value = this.getValue(id);
+ const value = this.getValue(id);
expectIsType(id, value, 'string');
return /** @type {string} */ (value);
},
@@ -96,11 +97,12 @@ function LoadTimeData(){}
* @return {string} The formatted string.
*/
getStringF: function(id, var_args) {
- var value = this.getString(id);
- if (!value)
+ const value = this.getString(id);
+ if (!value) {
return '';
+ }
- var args = Array.prototype.slice.call(arguments);
+ const args = Array.prototype.slice.call(arguments);
args[0] = value;
return this.substituteString.apply(this, args);
},
@@ -130,7 +132,7 @@ function LoadTimeData(){}
* @return {string} The formatted string.
*/
substituteString: function(label, var_args) {
- var varArgs = arguments;
+ const varArgs = arguments;
return label.replace(/\$(.|$|\n)/g, function(m) {
assert(m.match(/\$[$1-9]/), 'Unescaped $ found in localized string.');
return m == '$$' ? '$' : varArgs[m[1]];
@@ -149,11 +151,11 @@ function LoadTimeData(){}
* string pieces.
*/
getSubstitutedStringPieces: function(label, var_args) {
- var varArgs = arguments;
+ const varArgs = arguments;
// Split the string by separately matching all occurrences of $1-9 and of
// non $1-9 pieces.
- var pieces = (label.match(/(\$[1-9])|(([^$]|\$([^1-9]|$))+)/g) ||
- []).map(function(p) {
+ const pieces = (label.match(/(\$[1-9])|(([^$]|\$([^1-9]|$))+)/g) ||
+ []).map(function(p) {
// Pieces that are not $1-9 should be returned after replacing $$
// with $.
if (!p.match(/^\$[1-9]$/)) {
@@ -176,7 +178,7 @@ function LoadTimeData(){}
* @return {boolean} The corresponding boolean value.
*/
getBoolean: function(id) {
- var value = this.getValue(id);
+ const value = this.getValue(id);
expectIsType(id, value, 'boolean');
return /** @type {boolean} */ (value);
},
@@ -187,7 +189,7 @@ function LoadTimeData(){}
* @return {number} The corresponding number value.
*/
getInteger: function(id) {
- var value = this.getValue(id);
+ const value = this.getValue(id);
expectIsType(id, value, 'number');
expect(value == Math.floor(value), 'Number isn\'t integer: ' + value);
return /** @type {number} */ (value);
@@ -201,7 +203,7 @@ function LoadTimeData(){}
expect(
typeof replacements == 'object',
'Replacements must be a dictionary object.');
- for (var key in replacements) {
+ for (const key in replacements) {
this.data_[key] = replacements[key];
}
}
diff --git a/chromium/ui/webui/resources/js/parse_html_subset.js b/chromium/ui/webui/resources/js/parse_html_subset.js
index e1e57392041..b066ebd7b76 100644
--- a/chromium/ui/webui/resources/js/parse_html_subset.js
+++ b/chromium/ui/webui/resources/js/parse_html_subset.js
@@ -12,10 +12,10 @@
* @throws {Error} In case of non supported markup.
* @return {DocumentFragment} A document fragment containing the DOM tree.
*/
-var parseHtmlSubset = (function() {
+const parseHtmlSubset = (function() {
'use strict';
- var allowedAttributes = {
+ const allowedAttributes = {
'href': function(node, value) {
// Only allow a[href] starting with chrome:// and https://
return node.tagName == 'A' &&
@@ -33,16 +33,17 @@ var parseHtmlSubset = (function() {
* @type {!Array<string>}
* @const
*/
- var allowedTags = ['A', 'B', 'SPAN', 'STRONG'];
+ const allowedTags = ['A', 'B', 'SPAN', 'STRONG'];
/** @param {...Object} var_args Objects to merge. */
function merge(var_args) {
- var clone = {};
- for (var i = 0; i < arguments.length; ++i) {
+ const clone = {};
+ for (let i = 0; i < arguments.length; ++i) {
if (typeof arguments[i] == 'object') {
- for (var key in arguments[i]) {
- if (arguments[i].hasOwnProperty(key))
+ for (const key in arguments[i]) {
+ if (arguments[i].hasOwnProperty(key)) {
clone[key] = arguments[i][key];
+ }
}
}
}
@@ -51,41 +52,43 @@ var parseHtmlSubset = (function() {
function walk(n, f) {
f(n);
- for (var i = 0; i < n.childNodes.length; i++) {
+ for (let i = 0; i < n.childNodes.length; i++) {
walk(n.childNodes[i], f);
}
}
function assertElement(tags, node) {
- if (tags.indexOf(node.tagName) == -1)
+ if (tags.indexOf(node.tagName) == -1) {
throw Error(node.tagName + ' is not supported');
+ }
}
function assertAttribute(attrs, attrNode, node) {
- var n = attrNode.nodeName;
- var v = attrNode.nodeValue;
- if (!attrs.hasOwnProperty(n) || !attrs[n](node, v))
+ const n = attrNode.nodeName;
+ const v = attrNode.nodeValue;
+ if (!attrs.hasOwnProperty(n) || !attrs[n](node, v)) {
throw Error(node.tagName + '[' + n + '="' + v + '"] is not supported');
+ }
}
return function(s, opt_extraTags, opt_extraAttrs) {
- var extraTags = (opt_extraTags || []).map(function(str) {
+ const extraTags = (opt_extraTags || []).map(function(str) {
return str.toUpperCase();
});
- var tags = allowedTags.concat(extraTags);
- var attrs = merge(allowedAttributes, opt_extraAttrs || {});
+ const tags = allowedTags.concat(extraTags);
+ const attrs = merge(allowedAttributes, opt_extraAttrs || {});
- var doc = document.implementation.createHTMLDocument('');
- var r = doc.createRange();
+ const doc = document.implementation.createHTMLDocument('');
+ const r = doc.createRange();
r.selectNode(doc.body);
// This does not execute any scripts because the document has no view.
- var df = r.createContextualFragment(s);
+ const df = r.createContextualFragment(s);
walk(df, function(node) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
assertElement(tags, node);
- var nodeAttrs = node.attributes;
- for (var i = 0; i < nodeAttrs.length; ++i) {
+ const nodeAttrs = node.attributes;
+ for (let i = 0; i < nodeAttrs.length; ++i) {
assertAttribute(attrs, nodeAttrs[i], node);
}
break;
diff --git a/chromium/ui/webui/resources/js/promise_resolver.js b/chromium/ui/webui/resources/js/promise_resolver.js
index 64501d6d141..d19f7f73556 100644
--- a/chromium/ui/webui/resources/js/promise_resolver.js
+++ b/chromium/ui/webui/resources/js/promise_resolver.js
@@ -27,14 +27,31 @@ function PromiseResolver() {
/** @private {function(*=): void} */
this.reject_;
+ /** @private {boolean} */
+ this.isFulfilled_ = false;
+
/** @private {!Promise<T>} */
this.promise_ = new Promise(function(resolve, reject) {
- this.resolve_ = resolve;
- this.reject_ = reject;
+ this.resolve_ = /** @param {T=} resolution */ function(resolution) {
+ resolve(resolution);
+ this.isFulfilled_ = true;
+ };
+ this.reject_ = /** @param {*=} reason */ function(reason) {
+ reject(reason);
+ this.isFulfilled_ = true;
+ };
}.bind(this));
}
PromiseResolver.prototype = {
+ /** @return {boolean} Whether this resolver has been resolved or rejected. */
+ get isFulfilled() {
+ return this.isFulfilled_;
+ },
+ set isFulfilled(i) {
+ assertNotReached();
+ },
+
/** @return {!Promise<T>} */
get promise() {
return this.promise_;
diff --git a/chromium/ui/webui/resources/js/search_highlight_utils.js b/chromium/ui/webui/resources/js/search_highlight_utils.js
index 86725e5428a..5477b91a4a1 100644
--- a/chromium/ui/webui/resources/js/search_highlight_utils.js
+++ b/chromium/ui/webui/resources/js/search_highlight_utils.js
@@ -23,8 +23,9 @@ cr.define('cr.search_highlight_utils', function() {
function removeHighlights(wrappers) {
for (let wrapper of wrappers) {
// If wrapper is already removed, do nothing.
- if (!wrapper.parentElement)
+ if (!wrapper.parentElement) {
continue;
+ }
const textNode =
wrapper.querySelector(`.${ORIGINAL_CONTENT_CSS_CLASS}`).firstChild;
@@ -99,8 +100,9 @@ cr.define('cr.search_highlight_utils', function() {
let searchBubble = element.querySelector(`.${SEARCH_BUBBLE_CSS_CLASS}`);
// If the element has already been highlighted, there is no need to do
// anything.
- if (searchBubble)
+ if (searchBubble) {
return null;
+ }
searchBubble = document.createElement('div');
searchBubble.classList.add(SEARCH_BUBBLE_CSS_CLASS);
diff --git a/chromium/ui/webui/resources/js/template_data_externs.js b/chromium/ui/webui/resources/js/template_data_externs.js
index d5b8fb92906..4292824884c 100644
--- a/chromium/ui/webui/resources/js/template_data_externs.js
+++ b/chromium/ui/webui/resources/js/template_data_externs.js
@@ -8,4 +8,4 @@
*/
/** @type {!Object|undefined} */
-var templateData;
+let templateData;
diff --git a/chromium/ui/webui/resources/js/util.js b/chromium/ui/webui/resources/js/util.js
index 7139d9baede..081b2c2d0bc 100644
--- a/chromium/ui/webui/resources/js/util.js
+++ b/chromium/ui/webui/resources/js/util.js
@@ -13,7 +13,7 @@ function $(id) {
// Disable getElementById restriction here, since we are instructing other
// places to re-use the $() that is defined here.
// eslint-disable-next-line no-restricted-properties
- var el = document.getElementById(id);
+ const el = document.getElementById(id);
return el ? assertInstanceof(el, HTMLElement) : null;
}
@@ -28,7 +28,7 @@ function getSVGElement(id) {
// Disable getElementById restriction here, since it is not suitable for SVG
// elements.
// eslint-disable-next-line no-restricted-properties
- var el = document.getElementById(id);
+ const el = document.getElementById(id);
return el ? assertInstanceof(el, Element) : null;
}
@@ -37,7 +37,7 @@ function getSVGElement(id) {
* behind a shadow root), or null if nothing is focused.
*/
function getDeepActiveElement() {
- var a = document.activeElement;
+ let a = document.activeElement;
while (a && a.shadowRoot && a.shadowRoot.activeElement) {
a = a.shadowRoot.activeElement;
}
@@ -51,7 +51,7 @@ function getDeepActiveElement() {
* @param {string} msg The text to be pronounced.
*/
function announceAccessibleMessage(msg) {
- var element = document.createElement('div');
+ const element = document.createElement('div');
element.setAttribute('aria-live', 'polite');
element.style.position = 'fixed';
element.style.left = '-9999px';
@@ -72,7 +72,7 @@ function getUrlForCss(s) {
// http://www.w3.org/TR/css3-values/#uris
// Parentheses, commas, whitespace characters, single quotes (') and double
// quotes (") appearing in a URI must be escaped with a backslash
- var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
+ let s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
// WebKit has a bug when it comes to URLs that end with \
// https://bugs.webkit.org/show_bug.cgi?id=28885
if (/\\\\$/.test(s2)) {
@@ -88,11 +88,11 @@ function getUrlForCss(s) {
* @return {Object} Dictionary containing name value pairs for URL
*/
function parseQueryParams(location) {
- var params = {};
- var query = unescape(location.search.substring(1));
- var vars = query.split('&');
- for (var i = 0; i < vars.length; i++) {
- var pair = vars[i].split('=');
+ const params = {};
+ const query = unescape(location.search.substring(1));
+ const vars = query.split('&');
+ for (let i = 0; i < vars.length; i++) {
+ const pair = vars[i].split('=');
params[pair[0]] = pair[1];
}
return params;
@@ -107,11 +107,11 @@ function parseQueryParams(location) {
* @return {string} The constructed new URL.
*/
function setQueryParam(location, key, value) {
- var query = parseQueryParams(location);
+ const query = parseQueryParams(location);
query[encodeURIComponent(key)] = encodeURIComponent(value);
- var newQuery = '';
- for (var q in query) {
+ let newQuery = '';
+ for (const q in query) {
newQuery += (newQuery ? '&' : '?') + q + '=' + query[q];
}
@@ -137,7 +137,7 @@ function findAncestorByClass(el, className) {
* @return {Node} The found ancestor or null if not found.
*/
function findAncestor(node, predicate) {
- var last = false;
+ let last = false;
while (node != null && !(last = predicate(node))) {
node = node.parentNode;
}
@@ -145,12 +145,12 @@ function findAncestor(node, predicate) {
}
function swapDomNodes(a, b) {
- var afterA = a.nextSibling;
+ const afterA = a.nextSibling;
if (afterA == b) {
swapDomNodes(b, a);
return;
}
- var aParent = a.parentNode;
+ const aParent = a.parentNode;
b.parentNode.replaceChild(a, b);
aParent.insertBefore(b, afterA);
}
@@ -166,14 +166,16 @@ function swapDomNodes(a, b) {
function disableTextSelectAndDrag(opt_allowSelectStart, opt_allowDragStart) {
// Disable text selection.
document.onselectstart = function(e) {
- if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e)))
+ if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e))) {
e.preventDefault();
+ }
};
// Disable dragging.
document.ondragstart = function(e) {
- if (!(opt_allowDragStart && opt_allowDragStart.call(this, e)))
+ if (!(opt_allowDragStart && opt_allowDragStart.call(this, e))) {
e.preventDefault();
+ }
};
}
@@ -207,7 +209,7 @@ function getRequiredElement(id) {
* @return {!HTMLElement} the Element.
*/
function queryRequiredElement(selectors, opt_context) {
- var element = (opt_context || document).querySelector(selectors);
+ const element = (opt_context || document).querySelector(selectors);
return assertInstanceof(
element, HTMLElement, 'Missing required element: ' + selectors);
}
@@ -216,16 +218,18 @@ function queryRequiredElement(selectors, opt_context) {
// call into the browser to do the navigation.
['click', 'auxclick'].forEach(function(eventName) {
document.addEventListener(eventName, function(e) {
- if (e.button > 1)
- return; // Ignore buttons other than left and middle.
- if (e.defaultPrevented)
+ if (e.button > 1) {
+ return;
+ } // Ignore buttons other than left and middle.
+ if (e.defaultPrevented) {
return;
+ }
- var eventPath = e.path;
- var anchor = null;
+ const eventPath = e.path;
+ let anchor = null;
if (eventPath) {
- for (var i = 0; i < eventPath.length; i++) {
- var element = eventPath[i];
+ for (let i = 0; i < eventPath.length; i++) {
+ const element = eventPath[i];
if (element.tagName === 'A' && element.href) {
anchor = element;
break;
@@ -234,7 +238,7 @@ function queryRequiredElement(selectors, opt_context) {
}
// Fallback if Event.path is not available.
- var el = e.target;
+ let el = e.target;
if (!anchor && el.nodeType == Node.ELEMENT_NODE &&
el.webkitMatchesSelector('A, A *')) {
while (el.tagName != 'A') {
@@ -243,8 +247,9 @@ function queryRequiredElement(selectors, opt_context) {
anchor = el;
}
- if (!anchor)
+ if (!anchor) {
return;
+ }
anchor = /** @type {!HTMLAnchorElement} */ (anchor);
if ((anchor.protocol == 'file:' || anchor.protocol == 'about:') &&
@@ -267,10 +272,11 @@ function queryRequiredElement(selectors, opt_context) {
* @return {string} The new URL.
*/
function appendParam(url, key, value) {
- var param = encodeURIComponent(key) + '=' + encodeURIComponent(value);
+ const param = encodeURIComponent(key) + '=' + encodeURIComponent(value);
- if (url.indexOf('?') == -1)
+ if (url.indexOf('?') == -1) {
return url + '?' + param;
+ }
return url + '&' + param;
}
@@ -281,7 +287,7 @@ function appendParam(url, key, value) {
* @return {Element} The created element.
*/
function createElementWithClassName(type, className) {
- var elm = document.createElement(type);
+ const elm = document.createElement(type);
elm.className = className;
return elm;
}
@@ -297,21 +303,22 @@ function createElementWithClassName(type, className) {
*/
function ensureTransitionEndEvent(el, opt_timeOut) {
if (opt_timeOut === undefined) {
- var style = getComputedStyle(el);
+ const style = getComputedStyle(el);
opt_timeOut = parseFloat(style.transitionDuration) * 1000;
// Give an additional 50ms buffer for the animation to complete.
opt_timeOut += 50;
}
- var fired = false;
+ let fired = false;
el.addEventListener('transitionend', function f(e) {
el.removeEventListener('transitionend', f);
fired = true;
});
window.setTimeout(function() {
- if (!fired)
+ if (!fired) {
cr.dispatchSimpleEvent(el, 'transitionend', true);
+ }
}, opt_timeOut);
}
@@ -378,8 +385,9 @@ function HTMLEscape(original) {
* appended.
*/
function elide(original, maxLength) {
- if (original.length <= maxLength)
+ if (original.length <= maxLength) {
return original;
+ }
return original.substring(0, maxLength - 1) + '\u2026';
}
@@ -402,10 +410,11 @@ function quoteString(str) {
* optional return value is passed on by the listener.
*/
function listenOnce(target, eventNames, callback) {
- if (!Array.isArray(eventNames))
+ if (!Array.isArray(eventNames)) {
eventNames = eventNames.split(/ +/);
+ }
- var removeAllAndCallCallback = function(event) {
+ const removeAllAndCallCallback = function(event) {
eventNames.forEach(function(eventName) {
target.removeEventListener(eventName, removeAllAndCallCallback, false);
});
@@ -427,14 +436,16 @@ if (!('key' in KeyboardEvent.prototype)) {
/** @this {KeyboardEvent} */
get: function() {
// 0-9
- if (this.keyCode >= 0x30 && this.keyCode <= 0x39)
+ if (this.keyCode >= 0x30 && this.keyCode <= 0x39) {
return String.fromCharCode(this.keyCode);
+ }
// A-Z
if (this.keyCode >= 0x41 && this.keyCode <= 0x5a) {
- var result = String.fromCharCode(this.keyCode).toLowerCase();
- if (this.shiftKey)
+ let result = String.fromCharCode(this.keyCode).toLowerCase();
+ if (this.shiftKey) {
result = result.toUpperCase();
+ }
return result;
}
diff --git a/chromium/ui/webui/resources/js/web_ui_listener_behavior.js b/chromium/ui/webui/resources/js/web_ui_listener_behavior.js
index 35611ba1642..c25f390a2d2 100644
--- a/chromium/ui/webui/resources/js/web_ui_listener_behavior.js
+++ b/chromium/ui/webui/resources/js/web_ui_listener_behavior.js
@@ -8,6 +8,7 @@
*/
/** @polymerBehavior */
+// eslint-disable-next-line no-var
var WebUIListenerBehavior = {
properties: {
/**
diff --git a/chromium/ui/webui/resources/js/webui_listener_tracker.js b/chromium/ui/webui/resources/js/webui_listener_tracker.js
deleted file mode 100644
index 51ffb08cfb9..00000000000
--- a/chromium/ui/webui/resources/js/webui_listener_tracker.js
+++ /dev/null
@@ -1,42 +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.
-
-/**
- * @fileoverview Class that manages the addition and removal of WebUI
- * listeners.
- */
-
-/**
- * Create a WebUIListenerTracker to track a set of Web UI listeners.
- * @constructor
- */
-function WebUIListenerTracker() {
- /**
- * The Web UI listeners being tracked.
- * @private {!Array<!WebUIListener>}
- */
- this.listeners_ = [];
-}
-
-WebUIListenerTracker.prototype = {
- /**
- * Adds a WebUI listener to the array of listeners being tracked, which
- * will be removed when removeAll() is called.
- * Do not use this method if the listener will be removed manually.
- * @param {string} eventName The event to listen to.
- * @param {!Function} callback The callback to run when the event is fired.
- */
- add: function(eventName, callback) {
- this.listeners_.push(cr.addWebUIListener(eventName, callback));
- },
-
- /**
- * Removes all Web UI listeners that are currently being tracked.
- */
- removeAll: function() {
- while (this.listeners_.length > 0) {
- cr.removeWebUIListener(this.listeners_.pop());
- }
- },
-};
diff --git a/chromium/ui/webui/resources/js/webui_resource_test.js b/chromium/ui/webui/resources/js/webui_resource_test.js
index ea7089b0bac..0ab10df30c8 100644
--- a/chromium/ui/webui/resources/js/webui_resource_test.js
+++ b/chromium/ui/webui/resources/js/webui_resource_test.js
@@ -11,10 +11,11 @@
*/
function assertEquals(expected, observed, opt_message) {
if (observed !== expected) {
- var message = 'Assertion Failed\n Observed: ' + observed +
+ let message = 'Assertion Failed\n Observed: ' + observed +
'\n Expected: ' + expected;
- if (opt_message)
+ if (opt_message) {
message = message + '\n ' + opt_message;
+ }
throw new Error(message);
}
}
@@ -48,10 +49,11 @@ function assertFalse(observed, opt_message) {
*/
function assertNotEqual(reference, observed, opt_message) {
if (observed === reference) {
- var message = 'Assertion Failed\n Observed: ' + observed +
+ let message = 'Assertion Failed\n Observed: ' + observed +
'\n Reference: ' + reference;
- if (opt_message)
+ if (opt_message) {
message = message + '\n ' + opt_message;
+ }
throw new Error(message);
}
}
@@ -61,14 +63,15 @@ function assertNotEqual(reference, observed, opt_message) {
* @param {!Function} f The test function.
*/
function assertThrows(f) {
- var triggeredError = false;
+ let triggeredError = false;
try {
f();
} catch (err) {
triggeredError = true;
}
- if (!triggeredError)
+ if (!triggeredError) {
throw new Error('Assertion Failed: throw expected.');
+ }
}
/**
@@ -77,11 +80,11 @@ function assertThrows(f) {
* @param {!Array} observed The actual result.
*/
function assertArrayEquals(expected, observed) {
- var v1 = Array.prototype.slice.call(expected);
- var v2 = Array.prototype.slice.call(observed);
- var equal = v1.length == v2.length;
+ const v1 = Array.prototype.slice.call(expected);
+ const v2 = Array.prototype.slice.call(observed);
+ let equal = v1.length == v2.length;
if (equal) {
- for (var i = 0; i < v1.length; i++) {
+ for (let i = 0; i < v1.length; i++) {
if (v1[i] !== v2[i]) {
equal = false;
break;
@@ -89,7 +92,7 @@ function assertArrayEquals(expected, observed) {
}
}
if (!equal) {
- var message =
+ const message =
['Assertion Failed', 'Observed: ' + v2, 'Expected: ' + v1].join('\n ');
throw new Error(message);
}
@@ -103,11 +106,11 @@ function assertArrayEquals(expected, observed) {
function assertDeepEquals(expected, observed, opt_message) {
if (typeof expected == 'object' && expected != null) {
assertNotEqual(null, observed);
- for (var key in expected) {
+ for (const key in expected) {
assertTrue(key in observed, opt_message);
assertDeepEquals(expected[key], observed[key], opt_message);
}
- for (var key in observed) {
+ for (const key in observed) {
assertTrue(key in expected, opt_message);
}
} else {
@@ -136,55 +139,55 @@ function assertDeepEquals(expected, observed, opt_message) {
* tearDown: (function(): void|undefined),
* }}
*/
-var WebUiTestHarness;
+let WebUiTestHarness;
/**
* Scope containing testXXX functions.
* @type {!Object}
*/
-var testScope = {};
+let testScope = {};
/**
* Test harness entrypoints on |testScope|.
* @type {!WebUiTestHarness}
*/
-var testHarness = {};
+let testHarness = {};
/**
* List of test cases.
* @type {Array<string>} List of function names for tests to run.
*/
-var testCases = [];
+const testCases = [];
/**
* Indicates if all tests have run successfully.
* @type {boolean}
*/
-var cleanTestRun = true;
+let cleanTestRun = true;
/**
* Armed during setup of a test to call the matching tear down code.
* @type {Function}
*/
-var pendingTearDown = null;
+let pendingTearDown = null;
/**
* Name of current test.
* @type {?string}
*/
-var testName = null;
+let testName = null;
/**
* Time current test started.
* @type {number}
*/
-var testStartTime = 0;
+let testStartTime = 0;
/**
* Time first test started.
* @type {number}
*/
-var runnerStartTime = 0;
+let runnerStartTime = 0;
/**
* Runs all functions starting with test and reports success or
@@ -196,18 +199,20 @@ function runTests(opt_testScope) {
runnerStartTime = performance.now();
testScope = opt_testScope || window;
testHarness = /** @type{!WebUiTestHarness} */ (testScope);
- for (var name in testScope) {
+ for (const name in testScope) {
// To avoid unnecessary getting properties, test name first.
- if (/^test/.test(name) && typeof testScope[name] == 'function')
+ if (/^test/.test(name) && typeof testScope[name] == 'function') {
testCases.push(name);
+ }
}
if (!testCases.length) {
console.error('Failed to find test cases.');
cleanTestRun = false;
}
try {
- if (testHarness.setUpPage)
+ if (testHarness.setUpPage) {
testHarness.setUpPage();
+ }
} catch (err) {
cleanTestRun = false;
}
@@ -232,16 +237,17 @@ function startTesting() {
* last asynchronous test failed.
*/
function continueTesting(opt_asyncTestFailure) {
- var now = performance.now();
+ const now = performance.now();
if (testName) {
console.log(
'TEST ' + testName +
' complete, status=' + (opt_asyncTestFailure ? 'FAIL' : 'PASS') +
', duration=' + Math.round(now - testStartTime) + 'ms');
}
- if (opt_asyncTestFailure)
+ if (opt_asyncTestFailure) {
cleanTestRun = false;
- var done = false;
+ }
+ let done = false;
if (pendingTearDown) {
pendingTearDown();
pendingTearDown = null;
@@ -250,11 +256,12 @@ function continueTesting(opt_asyncTestFailure) {
testStartTime = now;
testName = testCases.pop();
console.log('TEST ' + testName + ' starting...');
- var isAsyncTest = testScope[testName].length;
- var testError = false;
+ const isAsyncTest = testScope[testName].length;
+ let testError = false;
try {
- if (testHarness.setUp)
+ if (testHarness.setUp) {
testHarness.setUp();
+ }
pendingTearDown = testHarness.tearDown || null;
testScope[testName](continueTesting);
} catch (err) {
@@ -265,8 +272,9 @@ function continueTesting(opt_asyncTestFailure) {
}
// Asynchronous tests must manually call continueTesting when complete
// unless they throw an exception.
- if (!isAsyncTest || testError)
+ if (!isAsyncTest || testError) {
continueTesting();
+ }
} else {
done = true;
endTests(cleanTestRun);
@@ -281,7 +289,8 @@ function continueTesting(opt_asyncTestFailure) {
* @param {boolean} success Indicates if the test completed successfully.
*/
function endTests(success) {
- var duration = runnerStartTime == 0 ? 0 : performance.now() - runnerStartTime;
+ const duration =
+ runnerStartTime == 0 ? 0 : performance.now() - runnerStartTime;
console.log(
'TEST all complete, status=' + (success ? 'PASS' : 'FAIL') +
', duration=' + Math.round(duration) + 'ms');
diff --git a/chromium/ui/webui/resources/polymer_resources.grdp b/chromium/ui/webui/resources/polymer_resources.grdp
index dd29898881a..a0c34db4542 100644
--- a/chromium/ui/webui/resources/polymer_resources.grdp
+++ b/chromium/ui/webui/resources/polymer_resources.grdp
@@ -72,22 +72,24 @@
file="../../../third_party/polymer/v1_0/components-chromium/iron-collapse/iron-collapse.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_DROPDOWN_IRON_DROPDOWN_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-dropdown/iron-dropdown-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_DROPDOWN_IRON_DROPDOWN_SCROLL_MANAGER_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-dropdown/iron-dropdown-scroll-manager-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_DROPDOWN_IRON_DROPDOWN_SCROLL_MANAGER_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-dropdown/iron-dropdown-scroll-manager.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_DROPDOWN_IRON_DROPDOWN_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-dropdown/iron-dropdown.html"
- type="chrome_html"
- compress="gzip" />
+ <if expr="chromeos">
+ <structure name="IDR_POLYMER_1_0_IRON_DROPDOWN_IRON_DROPDOWN_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/iron-dropdown/iron-dropdown-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_IRON_DROPDOWN_IRON_DROPDOWN_SCROLL_MANAGER_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/iron-dropdown/iron-dropdown-scroll-manager-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_IRON_DROPDOWN_IRON_DROPDOWN_SCROLL_MANAGER_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/iron-dropdown/iron-dropdown-scroll-manager.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_IRON_DROPDOWN_IRON_DROPDOWN_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/iron-dropdown/iron-dropdown.html"
+ type="chrome_html"
+ compress="gzip" />
+ </if>
<structure name="IDR_POLYMER_1_0_IRON_FIT_BEHAVIOR_IRON_FIT_BEHAVIOR_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/iron-fit-behavior/iron-fit-behavior-extracted.js"
type="chrome_html"
@@ -306,182 +308,88 @@
file="../../../third_party/polymer/v1_0/components-chromium/iron-selector/iron-selector.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_IN_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-in-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_IN_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-in-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_OUT_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-out-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_OUT_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-out-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_HERO_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/hero-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_HERO_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/hero-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_OPAQUE_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/opaque-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_OPAQUE_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/opaque-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SCALE_DOWN_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/scale-down-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SCALE_DOWN_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/scale-down-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_DOWN_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-down-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_DOWN_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-down-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_FROM_BOTTOM_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-from-bottom-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_FROM_BOTTOM_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-from-bottom-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_FROM_LEFT_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-from-left-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_FROM_LEFT_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-from-left-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_FROM_RIGHT_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-from-right-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_FROM_RIGHT_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-from-right-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_FROM_TOP_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-from-top-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_FROM_TOP_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-from-top-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_LEFT_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-left-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_LEFT_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-left-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_RIGHT_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-right-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_RIGHT_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-right-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_UP_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-up-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_UP_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-up-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_TRANSFORM_ANIMATION_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/transform-animation-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_TRANSFORM_ANIMATION_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/transform-animation.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable-behavior.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATED_PAGES_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animated-pages-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATED_PAGES_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animated-pages.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-behavior.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_RUNNER_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-runner-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_RUNNER_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-runner-behavior.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_SHARED_ELEMENT_ANIMATABLE_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-shared-element-animatable-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_SHARED_ELEMENT_ANIMATABLE_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-shared-element-animatable-behavior.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_SHARED_ELEMENT_ANIMATION_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-shared-element-animation-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_SHARED_ELEMENT_ANIMATION_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-shared-element-animation-behavior.html"
- type="chrome_html"
- compress="gzip" />
+ <if expr="chromeos">
+ <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_IN_ANIMATION_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-in-animation-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_IN_ANIMATION_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-in-animation.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_OUT_ANIMATION_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-out-animation-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_OUT_ANIMATION_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-out-animation.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_BEHAVIOR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable-behavior-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_BEHAVIOR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable-behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATED_PAGES_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animated-pages-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATED_PAGES_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animated-pages.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_BEHAVIOR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-behavior-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_BEHAVIOR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_RUNNER_BEHAVIOR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-runner-behavior-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_RUNNER_BEHAVIOR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-runner-behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_SHARED_ELEMENT_ANIMATABLE_BEHAVIOR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-shared-element-animatable-behavior-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_SHARED_ELEMENT_ANIMATABLE_BEHAVIOR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-shared-element-animatable-behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_SHARED_ELEMENT_ANIMATION_BEHAVIOR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-shared-element-animation-behavior-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_SHARED_ELEMENT_ANIMATION_BEHAVIOR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-shared-element-animation-behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ </if>
<structure name="IDR_POLYMER_1_0_NEON_ANIMATION_WEB_ANIMATIONS_HTML"
file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/web-animations.html"
type="chrome_html"
@@ -567,26 +475,6 @@
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"
@@ -604,14 +492,6 @@
file="../../../third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_SLIDER_PAPER_SLIDER_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_SLIDER_PAPER_SLIDER_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html"
- type="chrome_html"
- compress="gzip" />
<structure name="IDR_POLYMER_1_0_PAPER_SPINNER_PAPER_SPINNER_BEHAVIOR_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-behavior-extracted.js"
type="chrome_html"
diff --git a/chromium/ui/webui/resources/webui_resources.grd b/chromium/ui/webui/resources/webui_resources.grd
index 46c8b372f96..8cb513fdb45 100644
--- a/chromium/ui/webui/resources/webui_resources.grd
+++ b/chromium/ui/webui/resources/webui_resources.grd
@@ -175,6 +175,8 @@ without changes to the corresponding grd file. -->
file="images/2x/apps/button_butter_bar_close_pressed.png" type="BINDATA" />
<!-- Non-apps images -->
+ <include name="IDR_WEBUI_IMAGES_ADD"
+ file="images/add.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_CHECK"
file="images/check.png" type="BINDATA" />
<include name="IDR_WEBUI_IMAGES_CHECKBOX_BLACK"
@@ -185,6 +187,9 @@ without changes to the corresponding grd file. -->
file="images/disabled_select.png" type="BINDATA" />
<include name="IDR_WEBUI_IMAGES_ERROR"
file="images/error.svg" type="BINDATA" compress="gzip" />
+ <!-- Similar to IDR_WEBUI_IMAGES_ERROR except that it is white-filled instead of transparent-filled. Useful for badging images where the background may be red. -->
+ <include name="IDR_WEBUI_IMAGES_ERROR_BADGE"
+ file="images/error_badge.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_GOOGLE_LOGO"
file="images/google_logo.svg" type="BINDATA" compress="gzip" />
<include name="IDR_WEBUI_IMAGES_SELECT"
@@ -308,6 +313,9 @@ without changes to the corresponding grd file. -->
<structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_ROW"
file="html/cr/ui/focus_row.html" type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_ROW_BEHAVIOR"
+ file="html/cr/ui/focus_row_behavior.html" type="chrome_html"
+ compress="gzip" />
<structure name="IDR_WEBUI_HTML_CR_UI_LIST"
file="html/cr/ui/list.html"
type="chrome_html" compress="gzip" />
@@ -344,6 +352,14 @@ without changes to the corresponding grd file. -->
<structure name="IDR_WEBUI_HTML_CR_UI_SPLITTER"
file="html/cr/ui/splitter.html" type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_HTML_CR_UI_STORE"
+ file="html/cr/ui/store.html"
+ type="chrome_html" compress="gzip" />
+ <structure name="IDR_WEBUI_HTML_CR_UI_STORE_CLIENT"
+ file="html/cr/ui/store_client.html"
+ type="chrome_html" compress="gzip" />
+ <structure name="IDR_WEBUI_HTML_DARK_MODE"
+ file="html/dark_mode.html" type="chrome_html" compress="gzip" />
<structure name="IDR_WEBUI_HTML_EVENT_TRACKER"
file="html/event_tracker.html" type="chrome_html"
compress="gzip" />
@@ -360,9 +376,6 @@ without changes to the corresponding grd file. -->
compress="gzip" />
<structure name="IDR_WEBUI_HTML_UTIL"
file="html/util.html" type="chrome_html" compress="gzip" />
- <structure name="IDR_WEBUI_HTML_WEBUI_LISTENER_TRACKER"
- file="html/webui_listener_tracker.html" type="chrome_html"
- compress="gzip" />
<structure name="IDR_WEBUI_JS_ACTION_LINK"
file="js/action_link.js" type="chrome_html" compress="gzip" />
@@ -426,6 +439,9 @@ without changes to the corresponding grd file. -->
<structure name="IDR_WEBUI_JS_CR_UI_FOCUS_ROW"
file="js/cr/ui/focus_row.js" type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_JS_CR_UI_FOCUS_ROW_BEHAVIOR"
+ file="js/cr/ui/focus_row_behavior.js" type="chrome_html"
+ compress="gzip" />
<structure name="IDR_WEBUI_JS_CR_UI_LIST"
file="js/cr/ui/list.js" type="chrome_html" compress="gzip" />
<structure name="IDR_WEBUI_JS_CR_UI_LIST_ITEM"
@@ -466,6 +482,12 @@ without changes to the corresponding grd file. -->
<structure name="IDR_WEBUI_JS_CR_UI_SPLITTER"
file="js/cr/ui/splitter.js" type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_JS_CR_UI_STORE"
+ file="js/cr/ui/store.js"
+ type="chrome_html" compress="gzip" />
+ <structure name="IDR_WEBUI_JS_CR_UI_STORE_CLENT"
+ file="js/cr/ui/store_client.js"
+ type="chrome_html" compress="gzip" />
<structure name="IDR_WEBUI_JS_CR_UI_GRID"
file="js/cr/ui/grid.js" type="chrome_html" compress="gzip" />
<structure name="IDR_WEBUI_JS_CR_UI_REPEATING_BUTTON"
@@ -495,12 +517,12 @@ without changes to the corresponding grd file. -->
<structure name="IDR_WEBUI_JS_CR_UI_TOUCH_HANDLER"
file="js/cr/ui/touch_handler.js" type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_JS_DARK_MODE"
+ file="js/dark_mode.js" type="chrome_html"
+ compress="gzip" />
<structure name="IDR_WEBUI_JS_EVENT_TRACKER"
file="js/event_tracker.js" type="chrome_html"
compress="gzip" />
- <structure name="IDR_WEBUI_JS_WEBUI_LISTENER_TRACKER"
- file="js/webui_listener_tracker.js" type="chrome_html"
- compress="gzip" />
<structure name="IDR_WEBUI_JS_ICON"
file="js/icon.js" type="chrome_html" compress="gzip"
flattenhtml="true" />
diff --git a/chromium/ui/wm/core/base_focus_rules.cc b/chromium/ui/wm/core/base_focus_rules.cc
index eb446ee0fc9..6c17e453158 100644
--- a/chromium/ui/wm/core/base_focus_rules.cc
+++ b/chromium/ui/wm/core/base_focus_rules.cc
@@ -29,14 +29,14 @@ BaseFocusRules::BaseFocusRules() = default;
BaseFocusRules::~BaseFocusRules() = default;
bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
- aura::Window* window) const {
+ const aura::Window* window) const {
return window->IsVisible();
}
////////////////////////////////////////////////////////////////////////////////
// BaseFocusRules, FocusRules implementation:
-bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
+bool BaseFocusRules::IsToplevelWindow(const aura::Window* window) const {
// The window must in a valid hierarchy.
if (!window->GetRootWindow())
return false;
@@ -46,7 +46,7 @@ bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
return SupportsChildActivation(window->parent());
}
-bool BaseFocusRules::CanActivateWindow(aura::Window* window) const {
+bool BaseFocusRules::CanActivateWindow(const aura::Window* window) const {
// It is possible to activate a NULL window, it is equivalent to clearing
// activation.
if (!window)
@@ -76,7 +76,7 @@ bool BaseFocusRules::CanActivateWindow(aura::Window* window) const {
return !GetModalTransient(window);
}
-bool BaseFocusRules::CanFocusWindow(aura::Window* window,
+bool BaseFocusRules::CanFocusWindow(const aura::Window* window,
const ui::Event* event) const {
// It is possible to focus a NULL window, it is equivalent to clearing focus.
if (!window)
@@ -84,15 +84,16 @@ bool BaseFocusRules::CanFocusWindow(aura::Window* window,
// The focused window is always inside the active window, so windows that
// aren't activatable can't contain the focused window.
- aura::Window* activatable = GetActivatableWindow(window);
+ const aura::Window* activatable = GetActivatableWindow(window);
if (!activatable || !activatable->Contains(window))
return false;
return window->CanFocus();
}
-aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const {
- aura::Window* parent = window->parent();
- aura::Window* child = window;
+const aura::Window* BaseFocusRules::GetToplevelWindow(
+ const aura::Window* window) const {
+ const aura::Window* parent = window->parent();
+ const aura::Window* child = window;
while (parent) {
if (IsToplevelWindow(child))
return child;
@@ -104,35 +105,8 @@ aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const {
}
aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
- aura::Window* parent = window->parent();
- aura::Window* child = window;
- while (parent) {
- if (CanActivateWindow(child))
- return child;
-
- // CanActivateWindow() above will return false if |child| is blocked by a
- // modal transient. In this case the modal is or contains the activatable
- // window. We recurse because the modal may itself be blocked by a modal
- // transient.
- aura::Window* modal_transient = GetModalTransient(child);
- if (modal_transient)
- return GetActivatableWindow(modal_transient);
-
- if (wm::GetTransientParent(child)) {
- // To avoid infinite recursion, if |child| has a transient parent
- // whose own modal transient is |child| itself, just return |child|.
- aura::Window* parent_modal_transient =
- GetModalTransient(wm::GetTransientParent(child));
- if (parent_modal_transient == child)
- return child;
-
- return GetActivatableWindow(wm::GetTransientParent(child));
- }
-
- parent = parent->parent();
- child = child->parent();
- }
- return nullptr;
+ return const_cast<aura::Window*>(
+ GetActivatableWindow(const_cast<const aura::Window*>(window)));
}
aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
@@ -188,4 +162,37 @@ aura::Window* BaseFocusRules::GetNextActivatableWindow(
return nullptr;
}
+const aura::Window* BaseFocusRules::GetActivatableWindow(
+ const aura::Window* window) const {
+ const aura::Window* parent = window->parent();
+ const aura::Window* child = window;
+ while (parent) {
+ if (CanActivateWindow(child))
+ return child;
+
+ // CanActivateWindow() above will return false if |child| is blocked by a
+ // modal transient. In this case the modal is or contains the activatable
+ // window. We recurse because the modal may itself be blocked by a modal
+ // transient.
+ const aura::Window* modal_transient = GetModalTransient(child);
+ if (modal_transient)
+ return GetActivatableWindow(modal_transient);
+
+ if (wm::GetTransientParent(child)) {
+ // To avoid infinite recursion, if |child| has a transient parent
+ // whose own modal transient is |child| itself, just return |child|.
+ const aura::Window* parent_modal_transient =
+ GetModalTransient(wm::GetTransientParent(child));
+ if (parent_modal_transient == child)
+ return child;
+
+ return GetActivatableWindow(wm::GetTransientParent(child));
+ }
+
+ parent = parent->parent();
+ child = child->parent();
+ }
+ return nullptr;
+}
+
} // namespace wm
diff --git a/chromium/ui/wm/core/base_focus_rules.h b/chromium/ui/wm/core/base_focus_rules.h
index 6adf8794b53..52caf7f25d8 100644
--- a/chromium/ui/wm/core/base_focus_rules.h
+++ b/chromium/ui/wm/core/base_focus_rules.h
@@ -19,23 +19,30 @@ class WM_CORE_EXPORT BaseFocusRules : public FocusRules {
~BaseFocusRules() override;
// Returns true if the children of |window| can be activated.
- virtual bool SupportsChildActivation(aura::Window* window) const = 0;
+ virtual bool SupportsChildActivation(const aura::Window* window) const = 0;
// Returns true if |window| is considered visible for activation purposes.
virtual bool IsWindowConsideredVisibleForActivation(
- aura::Window* window) const;
+ const aura::Window* window) const;
// Overridden from FocusRules:
- bool IsToplevelWindow(aura::Window* window) const override;
- bool CanActivateWindow(aura::Window* window) const override;
- bool CanFocusWindow(aura::Window* window,
+ bool IsToplevelWindow(const aura::Window* window) const override;
+ bool CanActivateWindow(const aura::Window* window) const override;
+ bool CanFocusWindow(const aura::Window* window,
const ui::Event* event) const override;
- aura::Window* GetToplevelWindow(aura::Window* window) const override;
+ const aura::Window* GetToplevelWindow(
+ const aura::Window* window) const override;
aura::Window* GetActivatableWindow(aura::Window* window) const override;
aura::Window* GetFocusableWindow(aura::Window* window) const override;
aura::Window* GetNextActivatableWindow(aura::Window* ignore) const override;
private:
+ aura::Window* GetToplevelWindow(aura::Window* window) const {
+ return const_cast<aura::Window*>(
+ GetToplevelWindow(const_cast<const aura::Window*>(window)));
+ }
+ const aura::Window* GetActivatableWindow(const aura::Window* window) const;
+
DISALLOW_COPY_AND_ASSIGN(BaseFocusRules);
};
diff --git a/chromium/ui/wm/core/compound_event_filter.cc b/chromium/ui/wm/core/compound_event_filter.cc
index dcb640d3ba1..08c2ce58b76 100644
--- a/chromium/ui/wm/core/compound_event_filter.cc
+++ b/chromium/ui/wm/core/compound_event_filter.cc
@@ -4,7 +4,6 @@
#include "ui/wm/core/compound_event_filter.h"
-#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "ui/aura/client/cursor_client.h"
diff --git a/chromium/ui/wm/core/default_activation_client.cc b/chromium/ui/wm/core/default_activation_client.cc
index ee8ac40d584..4f7615bff79 100644
--- a/chromium/ui/wm/core/default_activation_client.cc
+++ b/chromium/ui/wm/core/default_activation_client.cc
@@ -110,15 +110,17 @@ const aura::Window* DefaultActivationClient::GetActiveWindow() const {
}
aura::Window* DefaultActivationClient::GetActivatableWindow(
- aura::Window* window) {
+ aura::Window* window) const {
return nullptr;
}
-aura::Window* DefaultActivationClient::GetToplevelWindow(aura::Window* window) {
+const aura::Window* DefaultActivationClient::GetToplevelWindow(
+ const aura::Window* window) const {
return nullptr;
}
-bool DefaultActivationClient::CanActivateWindow(aura::Window* window) const {
+bool DefaultActivationClient::CanActivateWindow(
+ const aura::Window* window) const {
return true;
}
diff --git a/chromium/ui/wm/core/default_activation_client.h b/chromium/ui/wm/core/default_activation_client.h
index b7ff7bc6430..ff7817e04da 100644
--- a/chromium/ui/wm/core/default_activation_client.h
+++ b/chromium/ui/wm/core/default_activation_client.h
@@ -35,9 +35,10 @@ class WM_CORE_EXPORT DefaultActivationClient : public ActivationClient,
void ActivateWindow(aura::Window* window) override;
void DeactivateWindow(aura::Window* window) override;
const aura::Window* GetActiveWindow() const override;
- aura::Window* GetActivatableWindow(aura::Window* window) override;
- aura::Window* GetToplevelWindow(aura::Window* window) override;
- bool CanActivateWindow(aura::Window* window) const override;
+ aura::Window* GetActivatableWindow(aura::Window* window) const override;
+ const aura::Window* GetToplevelWindow(
+ const aura::Window* window) const override;
+ bool CanActivateWindow(const aura::Window* window) const override;
// Overridden from WindowObserver:
void OnWindowDestroyed(aura::Window* window) override;
diff --git a/chromium/ui/wm/core/focus_controller.cc b/chromium/ui/wm/core/focus_controller.cc
index 267d67f2c81..5ae041361ec 100644
--- a/chromium/ui/wm/core/focus_controller.cc
+++ b/chromium/ui/wm/core/focus_controller.cc
@@ -37,13 +37,7 @@ void StackTransientParentsBelowModalWindow(aura::Window* window) {
////////////////////////////////////////////////////////////////////////////////
// FocusController, public:
-FocusController::FocusController(FocusRules* rules)
- : active_window_(nullptr),
- focused_window_(nullptr),
- updating_focus_(false),
- updating_activation_(false),
- rules_(rules),
- observer_manager_(this) {
+FocusController::FocusController(FocusRules* rules) : rules_(rules) {
DCHECK(rules);
}
@@ -73,15 +67,17 @@ const aura::Window* FocusController::GetActiveWindow() const {
return active_window_;
}
-aura::Window* FocusController::GetActivatableWindow(aura::Window* window) {
+aura::Window* FocusController::GetActivatableWindow(
+ aura::Window* window) const {
return rules_->GetActivatableWindow(window);
}
-aura::Window* FocusController::GetToplevelWindow(aura::Window* window) {
+const aura::Window* FocusController::GetToplevelWindow(
+ const aura::Window* window) const {
return rules_->GetToplevelWindow(window);
}
-bool FocusController::CanActivateWindow(aura::Window* window) const {
+bool FocusController::CanActivateWindow(const aura::Window* window) const {
return rules_->CanActivateWindow(window);
}
@@ -191,7 +187,7 @@ void FocusController::FocusAndActivateWindow(
}
// Focusing a window also activates its containing activatable window. Note
- // that the rules could redirect activation activation and/or focus.
+ // that the rules could redirect activation and/or focus.
aura::Window* focusable = rules_->GetFocusableWindow(window);
aura::Window* activatable =
focusable ? rules_->GetActivatableWindow(focusable) : nullptr;
@@ -206,7 +202,7 @@ void FocusController::FocusAndActivateWindow(
// Activation change observers may change the focused window. If this happens
// we must not adjust the focus below since this will clobber that change.
aura::Window* last_focused_window = focused_window_;
- if (!updating_activation_) {
+ if (!pending_activation_.has_value()) {
aura::WindowTracker focusable_window_tracker;
if (focusable) {
focusable_window_tracker.Add(focusable);
@@ -215,20 +211,27 @@ void FocusController::FocusAndActivateWindow(
SetActiveWindow(reason, window, activatable);
if (!focusable_window_tracker.windows().empty())
focusable = focusable_window_tracker.Pop();
+ } else {
+ // Only allow the focused window to change, *not* the active window if
+ // called reentrantly.
+ DCHECK(!activatable || activatable == pending_activation_.value());
}
// If the window's ActivationChangeObserver shifted focus to a valid window,
// we don't want to focus the window we thought would be focused by default.
if (!updating_focus_) {
+ aura::Window* const new_active_window = pending_activation_.has_value()
+ ? pending_activation_.value()
+ : active_window_;
const bool activation_changed_focus =
last_focused_window != focused_window_;
if (!activation_changed_focus || !focused_window_) {
- if (active_window_ && focusable)
- DCHECK(active_window_->Contains(focusable));
+ if (new_active_window && focusable)
+ DCHECK(new_active_window->Contains(focusable));
SetFocusedWindow(focusable);
}
- if (active_window_ && focused_window_)
- DCHECK(active_window_->Contains(focused_window_));
+ if (new_active_window && focused_window_)
+ DCHECK(new_active_window->Contains(focused_window_));
}
}
@@ -279,7 +282,7 @@ void FocusController::SetActiveWindow(
ActivationChangeObserver::ActivationReason reason,
aura::Window* requested_window,
aura::Window* window) {
- if (updating_activation_)
+ if (pending_activation_)
return;
if (window == active_window_) {
@@ -294,19 +297,22 @@ void FocusController::SetActiveWindow(
if (window)
DCHECK_EQ(window, rules_->GetActivatableWindow(window));
- base::AutoReset<bool> updating_activation(&updating_activation_, true);
+ base::AutoReset<base::Optional<aura::Window*>> updating_activation(
+ &pending_activation_, base::make_optional(window));
aura::Window* lost_activation = active_window_;
// Allow for the window losing activation to be deleted during dispatch. If
// it is deleted pass NULL to observers instead of a deleted window.
aura::WindowTracker window_tracker;
if (lost_activation)
window_tracker.Add(lost_activation);
+
+ for (auto& observer : activation_observers_)
+ observer.OnWindowActivating(reason, window, active_window_);
+
if (active_window_ && observer_manager_.IsObserving(active_window_) &&
focused_window_ != active_window_) {
observer_manager_.Remove(active_window_);
}
- for (auto& observer : activation_observers_)
- observer.OnWindowActivating(reason, window, active_window_);
active_window_ = window;
if (active_window_ && !observer_manager_.IsObserving(active_window_))
observer_manager_.Add(active_window_);
@@ -355,7 +361,7 @@ void FocusController::WindowLostFocusFromDispositionChange(
if (!(active_window_ && active_window_->Contains(focused_window_)))
SetFocusedWindow(next_activatable);
} else if (window->Contains(focused_window_)) {
- if (updating_activation_) {
+ if (pending_activation_) {
// We're in the process of updating activation, most likely
// ActivationChangeObserver::OnWindowActivated() is changing something
// about the focused window (visibility perhaps). Temporarily set the
diff --git a/chromium/ui/wm/core/focus_controller.h b/chromium/ui/wm/core/focus_controller.h
index 1c857fea1c4..e88ac12ac1b 100644
--- a/chromium/ui/wm/core/focus_controller.h
+++ b/chromium/ui/wm/core/focus_controller.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/observer_list.h"
+#include "base/optional.h"
#include "base/scoped_observer.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window_observer.h"
@@ -55,9 +56,10 @@ class WM_CORE_EXPORT FocusController : public ActivationClient,
void ActivateWindow(aura::Window* window) override;
void DeactivateWindow(aura::Window* window) override;
const aura::Window* GetActiveWindow() const override;
- aura::Window* GetActivatableWindow(aura::Window* window) override;
- aura::Window* GetToplevelWindow(aura::Window* window) override;
- bool CanActivateWindow(aura::Window* window) const override;
+ aura::Window* GetActivatableWindow(aura::Window* window) const override;
+ const aura::Window* GetToplevelWindow(
+ const aura::Window* window) const override;
+ bool CanActivateWindow(const aura::Window* window) const override;
// Overridden from aura::client::FocusClient:
void AddObserver(aura::client::FocusChangeObserver* observer) override;
@@ -116,11 +118,14 @@ class WM_CORE_EXPORT FocusController : public ActivationClient,
void WindowFocusedFromInputEvent(aura::Window* window,
const ui::Event* event);
- aura::Window* active_window_;
- aura::Window* focused_window_;
+ aura::Window* active_window_ = nullptr;
+ aura::Window* focused_window_ = nullptr;
- bool updating_focus_;
- bool updating_activation_;
+ bool updating_focus_ = false;
+
+ // An optional value. It is set to the window being activated and is unset
+ // after it is activated.
+ base::Optional<aura::Window*> pending_activation_;
std::unique_ptr<FocusRules> rules_;
@@ -128,7 +133,7 @@ class WM_CORE_EXPORT FocusController : public ActivationClient,
base::ObserverList<aura::client::FocusChangeObserver>::Unchecked
focus_observers_;
- ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
+ ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_{this};
DISALLOW_COPY_AND_ASSIGN(FocusController);
};
diff --git a/chromium/ui/wm/core/focus_controller_unittest.cc b/chromium/ui/wm/core/focus_controller_unittest.cc
index 684cdea9d3a..ee499668eaa 100644
--- a/chromium/ui/wm/core/focus_controller_unittest.cc
+++ b/chromium/ui/wm/core/focus_controller_unittest.cc
@@ -25,6 +25,16 @@
#include "ui/wm/public/activation_change_observer.h"
#include "ui/wm/public/activation_client.h"
+// EXPECT_DCHECK executes statement and expects a DCHECK death when DCHECK is
+// enabled.
+#if DCHECK_IS_ON()
+#define EXPECT_DCHECK(statement, regex) \
+ EXPECT_DEATH_IF_SUPPORTED(statement, regex)
+#else
+#define EXPECT_DCHECK(statement, regex) \
+ { statement; }
+#endif
+
namespace wm {
class FocusNotificationObserver : public ActivationChangeObserver,
@@ -340,6 +350,53 @@ class FocusShiftingActivationObserver : public ActivationChangeObserver {
DISALLOW_COPY_AND_ASSIGN(FocusShiftingActivationObserver);
};
+class ActivateWhileActivatingObserver : public ActivationChangeObserver {
+ public:
+ ActivateWhileActivatingObserver(aura::Window* to_observe,
+ aura::Window* to_activate,
+ aura::Window* to_focus)
+ : to_observe_(to_observe),
+ to_activate_(to_activate),
+ to_focus_(to_focus) {
+ GetActivationClient(to_observe_->GetRootWindow())->AddObserver(this);
+ }
+ ~ActivateWhileActivatingObserver() override {
+ GetActivationClient(to_observe_->GetRootWindow())->RemoveObserver(this);
+ }
+
+ private:
+ // Overridden from ActivationChangeObserver:
+ void OnWindowActivating(ActivationReason reason,
+ aura::Window* gaining_active,
+ aura::Window* losing_active) override {
+ if (gaining_active != to_observe_)
+ return;
+
+ if (to_activate_)
+ ActivateWindow(to_activate_);
+ if (to_focus_)
+ FocusWindow(to_focus_);
+ }
+ void OnWindowActivated(ActivationReason reason,
+ aura::Window* gained_active,
+ aura::Window* lost_active) override {}
+
+ void ActivateWindow(aura::Window* window) {
+ GetActivationClient(to_observe_->GetRootWindow())->ActivateWindow(window);
+ }
+
+ void FocusWindow(aura::Window* window) {
+ aura::client::GetFocusClient(to_observe_->GetRootWindow())
+ ->FocusWindow(window);
+ }
+
+ aura::Window* to_observe_;
+ aura::Window* to_activate_;
+ aura::Window* to_focus_;
+
+ DISALLOW_COPY_AND_ASSIGN(ActivateWhileActivatingObserver);
+};
+
// BaseFocusRules subclass that allows basic overrides of focus/activation to
// be tested. This is intended more as a test that the override system works at
// all, rather than as an exhaustive set of use cases, those should be covered
@@ -354,18 +411,18 @@ class TestFocusRules : public BaseFocusRules {
}
// Overridden from BaseFocusRules:
- bool SupportsChildActivation(aura::Window* window) const override {
+ bool SupportsChildActivation(const aura::Window* window) const override {
// In FocusControllerTests, only the RootWindow has activatable children.
return window->GetRootWindow() == window;
}
- bool CanActivateWindow(aura::Window* window) const override {
+ bool CanActivateWindow(const aura::Window* window) const override {
// Restricting focus to a non-activatable child window means the activatable
// parent outside the focus restriction is activatable.
bool can_activate =
CanFocusOrActivate(window) || window->Contains(focus_restriction_);
return can_activate ? BaseFocusRules::CanActivateWindow(window) : false;
}
- bool CanFocusWindow(aura::Window* window,
+ bool CanFocusWindow(const aura::Window* window,
const ui::Event* event) const override {
return CanFocusOrActivate(window)
? BaseFocusRules::CanFocusWindow(window, event)
@@ -387,7 +444,7 @@ class TestFocusRules : public BaseFocusRules {
}
private:
- bool CanFocusOrActivate(aura::Window* window) const {
+ bool CanFocusOrActivate(const aura::Window* window) const {
return !focus_restriction_ || focus_restriction_->Contains(window);
}
@@ -498,6 +555,7 @@ class FocusControllerTestBase : public aura::test::AuraTestBase {
virtual void DontPassDeletedWindow() {}
virtual void StackWindowAtTopOnActivation() {}
virtual void HideFocusedWindowDuringActivationLoss() {}
+ virtual void ActivateWhileActivating() {}
private:
std::unique_ptr<FocusController> focus_controller_;
@@ -914,6 +972,66 @@ class FocusControllerDirectTestBase : public FocusControllerTestBase {
}
}
+ // Tests that activating a window while a window is being activated is a
+ // no-op.
+ void ActivateWhileActivating() override {
+ aura::Window* w1 = root_window()->GetChildById(1);
+ aura::Window* w2 = root_window()->GetChildById(2);
+
+ ActivateWindowById(3);
+ // Activate a window while it is being activated does not DCHECK and the
+ // window is made active.
+ {
+ ActivateWhileActivatingObserver observer(/*to_observe=*/w1,
+ /*to_activate=*/w1,
+ /*to_focus=*/nullptr);
+ ActivateWindow(w1);
+ EXPECT_EQ(1, GetActiveWindowId());
+ }
+
+ ActivateWindowById(3);
+ // Focus a window while it is being activated does not DCHECK and the
+ // window is made active and focused.
+ {
+ ActivateWhileActivatingObserver observer(/*to_observe=*/w1,
+ /*to_activate=*/nullptr,
+ /*to_focus=*/w1);
+ ActivateWindow(w1);
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(1, GetFocusedWindowId());
+ }
+
+ ActivateWindowById(3);
+ // Shift focus while activating a window is allowed as long as it does
+ // not attempt to activate a different window.
+ {
+ aura::Window* w11 = root_window()->GetChildById(11);
+ aura::Window* w12 = root_window()->GetChildById(12);
+ ActivateWhileActivatingObserver observer(/*to_observe=*/w1,
+ /*to_activate=*/nullptr,
+ /*to_focus=*/w12);
+ FocusWindow(w11);
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(12, GetFocusedWindowId());
+ }
+
+ ActivateWindowById(3);
+ // Activate a different window while activating one fails. The window being
+ // activated in the 1st activation request will be activated.
+ {
+ ActivateWhileActivatingObserver observer(/*to_observe=*/w2,
+ /*to_activate=*/w1,
+ /*to_focus=*/nullptr);
+ // This should hit a DCHECK.
+ EXPECT_DCHECK(
+ {
+ ActivateWindow(w2);
+ EXPECT_EQ(2, GetActiveWindowId());
+ },
+ "");
+ }
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(FocusControllerDirectTestBase);
};
@@ -1364,6 +1482,8 @@ FOCUS_CONTROLLER_TEST(FocusControllerApiTest, StackWindowAtTopOnActivation);
FOCUS_CONTROLLER_TEST(FocusControllerApiTest,
HideFocusedWindowDuringActivationLoss);
+FOCUS_CONTROLLER_TEST(FocusControllerApiTest, ActivateWhileActivating);
+
// See description above TransientChildWindowActivationTest() for details.
FOCUS_CONTROLLER_TEST(FocusControllerParentHideTest,
TransientChildWindowActivationTest);
diff --git a/chromium/ui/wm/core/focus_rules.h b/chromium/ui/wm/core/focus_rules.h
index 8a29541d679..44644c9c9a6 100644
--- a/chromium/ui/wm/core/focus_rules.h
+++ b/chromium/ui/wm/core/focus_rules.h
@@ -27,13 +27,13 @@ class WM_CORE_EXPORT FocusRules {
// is considered toplevel is determined by a similar set of rules that
// govern activation and focus. Not all toplevel windows are activatable,
// call CanActivateWindow() to determine if a window can be activated.
- virtual bool IsToplevelWindow(aura::Window* window) const = 0;
+ virtual bool IsToplevelWindow(const aura::Window* window) const = 0;
// Returns true if |window| can be activated or focused.
- virtual bool CanActivateWindow(aura::Window* window) const = 0;
+ virtual bool CanActivateWindow(const aura::Window* window) const = 0;
// For CanFocusWindow(), NULL window is supported, because NULL is a valid
// focusable window (in the case of clearing focus).
// If |event| is non-null it is the event triggering the focus change.
- virtual bool CanFocusWindow(aura::Window* window,
+ virtual bool CanFocusWindow(const aura::Window* window,
const ui::Event* event) const = 0;
// Returns the toplevel window containing |window|. Not all toplevel windows
@@ -41,7 +41,9 @@ class WM_CORE_EXPORT FocusRules {
// activatable window, which might be in a different hierarchy.
// Will return NULL if |window| is not contained by a window considered to be
// a toplevel window.
- virtual aura::Window* GetToplevelWindow(aura::Window* window) const = 0;
+ virtual const aura::Window* GetToplevelWindow(
+ const aura::Window* window) const = 0;
+
// Returns the activatable or focusable window given an attempt to activate or
// focus |window|. Some possible scenarios (not intended to be exhaustive):
// - |window| is a child of a non-focusable window and so focus must be set
diff --git a/chromium/ui/wm/core/ime_util_chromeos.cc b/chromium/ui/wm/core/ime_util_chromeos.cc
index a77aa1582d3..e7c5e0274db 100644
--- a/chromium/ui/wm/core/ime_util_chromeos.cc
+++ b/chromium/ui/wm/core/ime_util_chromeos.cc
@@ -4,15 +4,23 @@
#include "ui/wm/core/ime_util_chromeos.h"
-#include "base/command_line.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/base/ui_base_switches.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/wm/core/coordinate_conversion.h"
namespace wm {
namespace {
+void SetWindowBoundsInScreen(aura::Window* window,
+ const gfx::Rect& bounds_in_screen) {
+ window->SetBoundsInScreen(
+ bounds_in_screen,
+ display::Screen::GetScreen()->GetDisplayNearestView(window));
+}
+
// Moves the window to ensure caret not in rect.
// Returns whether the window was moved or not.
void MoveWindowToEnsureCaretNotInRect(aura::Window* window,
@@ -24,24 +32,20 @@ void MoveWindowToEnsureCaretNotInRect(aura::Window* window,
}
// Calculate vertical window shift.
- gfx::Rect rect_in_root_window = rect_in_screen;
- ::wm::ConvertRectFromScreen(window->GetRootWindow(), &rect_in_root_window);
- gfx::Rect bounds_in_root_window = original_window_bounds;
- ::wm::ConvertRectFromScreen(window->GetRootWindow(), &bounds_in_root_window);
const int top_y =
- std::max(rect_in_root_window.y() - bounds_in_root_window.height(), 0);
+ std::max(rect_in_screen.y() - original_window_bounds.height(), 0);
// No need to move the window up.
- if (top_y >= bounds_in_root_window.y())
+ if (top_y >= original_window_bounds.y())
return;
// Set restore bounds and move the window.
window->SetProperty(kVirtualKeyboardRestoreBoundsKey,
new gfx::Rect(original_window_bounds));
- gfx::Rect new_bounds_in_root_window = bounds_in_root_window;
- new_bounds_in_root_window.set_y(top_y);
- window->SetBounds(new_bounds_in_root_window);
+ gfx::Rect new_bounds_in_screen = original_window_bounds;
+ new_bounds_in_screen.set_y(top_y);
+ SetWindowBoundsInScreen(window, new_bounds_in_screen);
}
} // namespace
@@ -62,9 +66,7 @@ void RestoreWindowBoundsOnClientFocusLost(aura::Window* window) {
// TODO(yhanada): Don't move the window if a user has moved it while the
// keyboard is shown.
if (window->GetBoundsInScreen() != *vk_restore_bounds) {
- gfx::Rect original_bounds = *vk_restore_bounds;
- ::wm::ConvertRectFromScreen(window->GetRootWindow(), &original_bounds);
- window->SetBounds(original_bounds);
+ SetWindowBoundsInScreen(window, *vk_restore_bounds);
}
window->ClearProperty(wm::kVirtualKeyboardRestoreBoundsKey);
}
diff --git a/chromium/ui/wm/core/shadow_controller.cc b/chromium/ui/wm/core/shadow_controller.cc
index 251f3e08ffd..5c1d6efe590 100644
--- a/chromium/ui/wm/core/shadow_controller.cc
+++ b/chromium/ui/wm/core/shadow_controller.cc
@@ -86,6 +86,8 @@ class ShadowController::Impl :
void OnWindowInitialized(aura::Window* window) override;
// aura::WindowObserver overrides:
+ void OnWindowParentChanged(aura::Window* window,
+ aura::Window* parent) override;
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) override;
@@ -164,6 +166,12 @@ void ShadowController::Impl::OnWindowInitialized(aura::Window* window) {
observer_manager_.Add(window);
}
+void ShadowController::Impl::OnWindowParentChanged(aura::Window* window,
+ aura::Window* parent) {
+ if (parent && window->IsVisible())
+ HandlePossibleShadowVisibilityChange(window);
+}
+
void ShadowController::Impl::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
diff --git a/chromium/ui/wm/core/shadow_controller_unittest.cc b/chromium/ui/wm/core/shadow_controller_unittest.cc
index 9d973ae0f29..8b61b5a35e0 100644
--- a/chromium/ui/wm/core/shadow_controller_unittest.cc
+++ b/chromium/ui/wm/core/shadow_controller_unittest.cc
@@ -32,8 +32,7 @@ class ShadowControllerTest : public aura::test::AuraTestBase {
void SetUp() override {
AuraTestBase::SetUp();
new wm::DefaultActivationClient(root_window());
- ActivationClient* activation_client = GetActivationClient(root_window());
- shadow_controller_.reset(new ShadowController(activation_client, nullptr));
+ InstallShadowController(nullptr);
}
void TearDown() override {
shadow_controller_.reset();
@@ -49,6 +48,13 @@ class ShadowControllerTest : public aura::test::AuraTestBase {
GetActivationClient(window->GetRootWindow())->ActivateWindow(window);
}
+ void InstallShadowController(
+ std::unique_ptr<ShadowControllerDelegate> delegate) {
+ ActivationClient* activation_client = GetActivationClient(root_window());
+ shadow_controller_ = std::make_unique<ShadowController>(
+ activation_client, std::move(delegate));
+ }
+
private:
std::unique_ptr<ShadowController> shadow_controller_;
@@ -225,4 +231,37 @@ TEST_F(ShadowControllerTest, TransientParentKeepsActiveShadow) {
EXPECT_EQ(kShadowElevationActiveWindow, shadow1->desired_elevation());
}
+namespace {
+
+class TestShadowControllerDelegate : public wm::ShadowControllerDelegate {
+ public:
+ TestShadowControllerDelegate() {}
+ ~TestShadowControllerDelegate() override {}
+
+ bool ShouldShowShadowForWindow(const aura::Window* window) override {
+ return window->parent();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestShadowControllerDelegate);
+};
+
+} // namespace
+
+TEST_F(ShadowControllerTest, UpdateShadowWhenAddedToParent) {
+ InstallShadowController(std::make_unique<TestShadowControllerDelegate>());
+ std::unique_ptr<aura::Window> window1(new aura::Window(NULL));
+ window1->SetType(aura::client::WINDOW_TYPE_NORMAL);
+ window1->Init(ui::LAYER_TEXTURED);
+ window1->SetBounds(gfx::Rect(10, 20, 300, 400));
+ window1->Show();
+ EXPECT_FALSE(ShadowController::GetShadowForWindow(window1.get()));
+
+ ParentWindow(window1.get());
+
+ ASSERT_TRUE(ShadowController::GetShadowForWindow(window1.get()));
+ EXPECT_TRUE(
+ ShadowController::GetShadowForWindow(window1.get())->layer()->visible());
+}
+
} // namespace wm
diff --git a/chromium/ui/wm/core/shadow_types.cc b/chromium/ui/wm/core/shadow_types.cc
index 5bfb680e7c6..6b44b5efbbe 100644
--- a/chromium/ui/wm/core/shadow_types.cc
+++ b/chromium/ui/wm/core/shadow_types.cc
@@ -17,7 +17,6 @@ void SetShadowElevation(aura::Window* window, int elevation) {
int GetDefaultShadowElevationForWindow(const aura::Window* window) {
switch (window->type()) {
case aura::client::WINDOW_TYPE_NORMAL:
- case aura::client::WINDOW_TYPE_PANEL:
return kShadowElevationInactiveWindow;
case aura::client::WINDOW_TYPE_MENU:
diff --git a/chromium/ui/wm/core/window_modality_controller.cc b/chromium/ui/wm/core/window_modality_controller.cc
index 44fbc4f8713..c3503e62036 100644
--- a/chromium/ui/wm/core/window_modality_controller.cc
+++ b/chromium/ui/wm/core/window_modality_controller.cc
@@ -25,27 +25,28 @@
namespace wm {
namespace {
-bool HasAncestor(aura::Window* window, aura::Window* ancestor) {
+bool HasAncestor(const aura::Window* window, const aura::Window* ancestor) {
return ancestor && ancestor->Contains(window);
}
-bool TransientChildIsWindowModal(aura::Window* window) {
+bool TransientChildIsWindowModal(const aura::Window* window) {
return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW;
}
-bool TransientChildIsSystemModal(aura::Window* window) {
+bool TransientChildIsSystemModal(const aura::Window* window) {
return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM;
}
-bool TransientChildIsChildModal(aura::Window* window) {
+bool TransientChildIsChildModal(const aura::Window* window) {
return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_CHILD;
}
-aura::Window* GetModalParent(aura::Window* window) {
+aura::Window* GetModalParent(const aura::Window* window) {
return window->GetProperty(aura::client::kChildModalParentKey);
}
-bool IsModalTransientChild(aura::Window* transient, aura::Window* original) {
+bool IsModalTransientChild(const aura::Window* transient,
+ const aura::Window* original) {
return transient->IsVisible() &&
(TransientChildIsWindowModal(transient) ||
TransientChildIsSystemModal(transient) ||
@@ -53,14 +54,15 @@ bool IsModalTransientChild(aura::Window* transient, aura::Window* original) {
HasAncestor(original, GetModalParent(transient))));
}
-aura::Window* GetModalTransientChild(aura::Window* activatable,
- aura::Window* original) {
- for (aura::Window* transient : GetTransientChildren(activatable)) {
+const aura::Window* GetModalTransientChild(const aura::Window* activatable,
+ const aura::Window* original) {
+ for (const aura::Window* transient : GetTransientChildren(activatable)) {
if (IsModalTransientChild(transient, original)) {
if (GetTransientChildren(transient).empty())
return transient;
- aura::Window* modal_child = GetModalTransientChild(transient, original);
+ const aura::Window* modal_child =
+ GetModalTransientChild(transient, original);
return modal_child ? modal_child : transient;
}
}
@@ -74,11 +76,16 @@ void SetModalParent(aura::Window* child, aura::Window* parent) {
}
aura::Window* GetModalTransient(aura::Window* window) {
+ return const_cast<aura::Window*>(
+ GetModalTransient(const_cast<const aura::Window*>(window)));
+}
+
+const aura::Window* GetModalTransient(const aura::Window* window) {
if (!window)
return nullptr;
// We always want to check for the transient child of the toplevel window.
- aura::Window* toplevel = GetToplevelWindow(window);
+ const aura::Window* toplevel = GetToplevelWindow(window);
if (!toplevel)
return nullptr;
diff --git a/chromium/ui/wm/core/window_modality_controller.h b/chromium/ui/wm/core/window_modality_controller.h
index e9349e5aad3..8a9f9293b61 100644
--- a/chromium/ui/wm/core/window_modality_controller.h
+++ b/chromium/ui/wm/core/window_modality_controller.h
@@ -31,6 +31,8 @@ WM_CORE_EXPORT void SetModalParent(aura::Window* child, aura::Window* parent);
// Returns the modal transient child of |window|, or NULL if |window| does not
// have any modal transient children.
WM_CORE_EXPORT aura::Window* GetModalTransient(aura::Window* window);
+WM_CORE_EXPORT const aura::Window* GetModalTransient(
+ const aura::Window* window);
// WindowModalityController is an event filter that consumes events sent to
// windows that are the transient parents of window-modal windows. This filter
diff --git a/chromium/ui/wm/core/window_util.cc b/chromium/ui/wm/core/window_util.cc
index ed0f762fbfe..4fa23c0372f 100644
--- a/chromium/ui/wm/core/window_util.cc
+++ b/chromium/ui/wm/core/window_util.cc
@@ -77,11 +77,11 @@ bool IsActiveWindow(const aura::Window* window) {
return client && client->GetActiveWindow() == window;
}
-bool CanActivateWindow(aura::Window* window) {
+bool CanActivateWindow(const aura::Window* window) {
DCHECK(window);
if (!window->GetRootWindow())
return false;
- ActivationClient* client = GetActivationClient(window->GetRootWindow());
+ const ActivationClient* client = GetActivationClient(window->GetRootWindow());
return client && client->CanActivateWindow(window);
}
@@ -118,7 +118,7 @@ void SetWindowFullscreen(aura::Window* window, bool fullscreen) {
}
}
-bool WindowStateIs(aura::Window* window, ui::WindowShowState state) {
+bool WindowStateIs(const aura::Window* window, ui::WindowShowState state) {
return window->GetProperty(aura::client::kShowStateKey) == state;
}
@@ -140,7 +140,12 @@ aura::Window* GetActivatableWindow(aura::Window* window) {
}
aura::Window* GetToplevelWindow(aura::Window* window) {
- ActivationClient* client = GetActivationClient(window->GetRootWindow());
+ return const_cast<aura::Window*>(
+ GetToplevelWindow(const_cast<const aura::Window*>(window)));
+}
+
+const aura::Window* GetToplevelWindow(const aura::Window* window) {
+ const ActivationClient* client = GetActivationClient(window->GetRootWindow());
return client ? client->GetToplevelWindow(window) : NULL;
}
@@ -178,7 +183,7 @@ aura::Window* GetTransientParent(aura::Window* window) {
const aura::Window* GetTransientParent(const aura::Window* window) {
const TransientWindowManager* manager =
TransientWindowManager::GetIfExists(window);
- return manager ? manager->transient_parent() : NULL;
+ return manager ? manager->transient_parent() : nullptr;
}
const std::vector<aura::Window*>& GetTransientChildren(
@@ -192,6 +197,12 @@ const std::vector<aura::Window*>& GetTransientChildren(
return *shared;
}
+aura::Window* GetTransientRoot(aura::Window* window) {
+ while (window && GetTransientParent(window))
+ window = GetTransientParent(window);
+ return window;
+}
+
void AddTransientChild(aura::Window* parent, aura::Window* child) {
TransientWindowManager::GetOrCreate(parent)->AddTransientChild(child);
}
diff --git a/chromium/ui/wm/core/window_util.h b/chromium/ui/wm/core/window_util.h
index 919ceb1952a..1fa69d60886 100644
--- a/chromium/ui/wm/core/window_util.h
+++ b/chromium/ui/wm/core/window_util.h
@@ -29,11 +29,11 @@ namespace wm {
WM_CORE_EXPORT void ActivateWindow(aura::Window* window);
WM_CORE_EXPORT void DeactivateWindow(aura::Window* window);
WM_CORE_EXPORT bool IsActiveWindow(const aura::Window* window);
-WM_CORE_EXPORT bool CanActivateWindow(aura::Window* window);
+WM_CORE_EXPORT bool CanActivateWindow(const aura::Window* window);
WM_CORE_EXPORT void SetWindowFullscreen(aura::Window* window, bool fullscreen);
// Returns true if |window|'s show state is |state|.
-WM_CORE_EXPORT bool WindowStateIs(aura::Window* window,
+WM_CORE_EXPORT bool WindowStateIs(const aura::Window* window,
ui::WindowShowState state);
// Sets the window state to |state|.
@@ -50,6 +50,8 @@ WM_CORE_EXPORT aura::Window* GetActivatableWindow(aura::Window* window);
// Retrieves the toplevel window for |window|. The ActivationClient makes this
// determination.
WM_CORE_EXPORT aura::Window* GetToplevelWindow(aura::Window* window);
+WM_CORE_EXPORT const aura::Window* GetToplevelWindow(
+ const aura::Window* window);
// Returns the existing Layer for |root| (and all its descendants) and creates
// a new layer for |root| and all its descendants. This is intended for
@@ -80,7 +82,7 @@ WM_CORE_EXPORT std::unique_ptr<ui::LayerTreeOwner> MirrorLayers(
// Convenience functions that get the TransientWindowManager for the window and
// redirect appropriately. These are preferable to calling functions on
-// TransientWindowManager as they handle the appropriate NULL checks.
+// TransientWindowManager as they handle the appropriate null checks.
WM_CORE_EXPORT aura::Window* GetTransientParent(aura::Window* window);
WM_CORE_EXPORT const aura::Window* GetTransientParent(
const aura::Window* window);
@@ -90,6 +92,7 @@ WM_CORE_EXPORT void AddTransientChild(aura::Window* parent,
aura::Window* child);
WM_CORE_EXPORT void RemoveTransientChild(aura::Window* parent,
aura::Window* child);
+WM_CORE_EXPORT aura::Window* GetTransientRoot(aura::Window* window);
// Returns true if |window| has |ancestor| as a transient ancestor. A transient
// ancestor is found by following the transient parent chain of the window.
diff --git a/chromium/ui/wm/public/activation_client.h b/chromium/ui/wm/public/activation_client.h
index a2b5ee714ec..c5315ceec37 100644
--- a/chromium/ui/wm/public/activation_client.h
+++ b/chromium/ui/wm/public/activation_client.h
@@ -40,14 +40,15 @@ class WM_PUBLIC_EXPORT ActivationClient {
// GetToplevelWindow() below), as the toplevel window may not be activatable
// (for example it may be blocked by a modal transient, or some other
// condition).
- virtual aura::Window* GetActivatableWindow(aura::Window* window) = 0;
+ virtual aura::Window* GetActivatableWindow(aura::Window* window) const = 0;
// Retrieves the toplevel window for |window|, or NULL if there is none.
- virtual aura::Window* GetToplevelWindow(aura::Window* window) = 0;
+ virtual const aura::Window* GetToplevelWindow(
+ const aura::Window* window) const = 0;
// Returns true if |window| can be activated, false otherwise. If |window| has
// a modal child it can not be activated.
- virtual bool CanActivateWindow(aura::Window* window) const = 0;
+ virtual bool CanActivateWindow(const aura::Window* window) const = 0;
protected:
virtual ~ActivationClient() {}
diff --git a/chromium/ui/wm/public/activation_delegate.cc b/chromium/ui/wm/public/activation_delegate.cc
index 79d48335811..f6ebe791949 100644
--- a/chromium/ui/wm/public/activation_delegate.cc
+++ b/chromium/ui/wm/public/activation_delegate.cc
@@ -18,7 +18,7 @@ void SetActivationDelegate(aura::Window* window, ActivationDelegate* delegate) {
window->SetProperty(kActivationDelegateKey, delegate);
}
-ActivationDelegate* GetActivationDelegate(aura::Window* window) {
+ActivationDelegate* GetActivationDelegate(const aura::Window* window) {
return window->GetProperty(kActivationDelegateKey);
}
diff --git a/chromium/ui/wm/public/activation_delegate.h b/chromium/ui/wm/public/activation_delegate.h
index 9fc83f41c6c..9d6bb343800 100644
--- a/chromium/ui/wm/public/activation_delegate.h
+++ b/chromium/ui/wm/public/activation_delegate.h
@@ -28,7 +28,7 @@ class WM_PUBLIC_EXPORT ActivationDelegate {
WM_PUBLIC_EXPORT void SetActivationDelegate(aura::Window* window,
ActivationDelegate* delegate);
WM_PUBLIC_EXPORT ActivationDelegate* GetActivationDelegate(
- aura::Window* window);
+ const aura::Window* window);
} // namespace wm